diff options
author | dec05eba <dec05eba@protonmail.com> | 2021-06-02 17:42:30 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2021-06-02 17:43:47 +0200 |
commit | cc3a65bde2e480b2b07b74eeef20d9081d7f730f (patch) | |
tree | 1bb5b85ab764592093e8042458ec9f4be0cf904a | |
parent | 1b6812348e75de21c8f398a7dc944cc427064cc4 (diff) |
Add modern theme
Join matrix room by their name instead of id if there is a name.
This allows you to join rooms where the homeserver that created the room
is no longer participating in the room.
-rw-r--r-- | TODO | 4 | ||||
-rw-r--r-- | include/Body.hpp | 28 | ||||
-rw-r--r-- | include/QuickMedia.hpp | 3 | ||||
-rw-r--r-- | include/RoundedRectangle.hpp | 5 | ||||
-rw-r--r-- | plugins/Page.hpp | 2 | ||||
-rw-r--r-- | shaders/rounded_rectangle.glsl | 8 | ||||
-rw-r--r-- | shaders/rounded_rectangle_mask.glsl | 17 | ||||
-rw-r--r-- | src/Body.cpp | 304 | ||||
-rw-r--r-- | src/QuickMedia.cpp | 136 | ||||
-rw-r--r-- | src/RoundedRectangle.cpp | 18 | ||||
-rw-r--r-- | src/SearchBar.cpp | 2 | ||||
-rw-r--r-- | src/VideoPlayer.cpp | 6 | ||||
-rw-r--r-- | src/plugins/FileManager.cpp | 12 | ||||
-rw-r--r-- | src/plugins/Fourchan.cpp | 4 | ||||
-rw-r--r-- | src/plugins/Matrix.cpp | 14 | ||||
-rw-r--r-- | src/plugins/Page.cpp | 4 | ||||
-rw-r--r-- | src/plugins/Youtube.cpp | 8 |
17 files changed, 372 insertions, 203 deletions
@@ -147,4 +147,6 @@ Ctrl+S saving a video should copy the video from cache if the video was download When synapse adds support for media download http request range then quickmedia should download the last 4096 bytes of mp4 files and move the moov atom and co64 atoms (and others) to the front of the file before mdat, similar to how qt-faststart does it. This is needed for video streaming certain mp4 files. Ctrl+S when a body item is selected on youtube/xxxplugins should show an option to download the video, instead of having to press ctrl+s after the video is playing. Show a subscribe button for channels, which should be red and say "subscribe" if we are not subscribed and it should be gray and say "unsubscribe" if we already are subscribed. -Display youtube playlists differently and support downloading the whole playlist at once.
\ No newline at end of file +Display youtube playlists differently and support downloading the whole playlist at once. +To fix jitter in body when items are added before the selected item, we should increase page_scroll by the height of the new item. +Cancel current search when search is updated.
\ No newline at end of file diff --git a/include/Body.hpp b/include/Body.hpp index 388d825..4846b59 100644 --- a/include/Body.hpp +++ b/include/Body.hpp @@ -30,7 +30,13 @@ namespace QuickMedia { enum class ThumbnailMaskType { NONE, - CIRCLE + CIRCLE, + ROUNDED_RECTANGLE + }; + + enum BodyTheme : int { + BODY_THEME_MINIMAL, + BODY_THEME_MODERN_SPACIOUS }; // TODO: Remove and create an Userdata class instead to replace the void* userdata in BodyItem @@ -183,7 +189,7 @@ namespace QuickMedia { class Body { public: - Body(Program *program, sf::Texture &loading_icon_texture, sf::Shader *rounded_rectangle_shader); + Body(BodyTheme body_theme, sf::Texture &loading_icon_texture, sf::Shader *rounded_rectangle_shader, sf::Shader *rounded_rectangle_mask_shader); ~Body(); // Select previous page, ignoring invisible items. Returns true if the item was changed. This can be used to check if the top was hit when wrap_around is set to false @@ -231,7 +237,6 @@ namespace QuickMedia { void draw_item(sf::RenderWindow &window, BodyItem *item, sf::Vector2f pos, sf::Vector2f size, bool include_embedded_item = true, bool is_embedded = false); float get_item_height(BodyItem *item, float width, bool load_texture = true, bool include_embedded_item = true, bool merge_with_previous = false, int item_index = -1); - float get_spacing_y() const; // TODO: Highlight the part of the text that matches the search. void filter_search_fuzzy(const std::string &text); @@ -254,14 +259,10 @@ namespace QuickMedia { void apply_search_filter_for_item(BodyItem *body_item); - sf::Text progress_text; - sf::Text replies_text; - sf::Text embedded_item_load_text; BodyItems items; bool draw_thumbnails; // Set to {0, 0} to disable resizing sf::Vector2i thumbnail_max_size; - sf::Color line_separator_color; BodyItemRenderCallback body_item_render_callback; BodyItemMergeHandler body_item_merge_handler; std::function<void(BodyItem*)> body_item_select_callback; @@ -269,10 +270,12 @@ namespace QuickMedia { AttachSide attach_side = AttachSide::TOP; bool title_mark_urls = false; bool swiping_enabled = false; + bool show_drop_shadow = true; std::function<void()> on_top_reached = nullptr; std::function<void()> on_bottom_reached = nullptr; private: + void draw_drop_shadow(sf::RenderWindow &window); void filter_search_fuzzy_item(const std::string &text, BodyItem *body_item); void handle_item_render(BodyItem *item, const sf::Vector2f pos, const sf::Vector2f size, const float item_height, int item_index); void draw_item(sf::RenderWindow &window, BodyItem *item, const sf::Vector2f &pos, const sf::Vector2f &size, const float item_height, const int item_index, const Json::Value &content_progress, bool include_embedded_item = true, bool merge_with_previous = false); @@ -302,7 +305,8 @@ namespace QuickMedia { BOTTOM }; - Program *program; + BodyTheme body_theme; + int selected_item; int prev_selected_item; double page_scroll = 0.0; @@ -312,6 +316,11 @@ namespace QuickMedia { //sf::RectangleShape item_separator; sf::Sprite image; sf::Sprite loading_icon; + + sf::Text progress_text; + sf::Text replies_text; + sf::Text embedded_item_load_text; + int num_visible_items; bool top_cut_off; bool bottom_cut_off; @@ -345,12 +354,15 @@ namespace QuickMedia { RoundedRectangle item_background; RoundedRectangle reaction_background; bool render_selected_item_bg = true; + float item_background_prev_pos_y = 0.0f; float item_background_target_pos_y = 0.0f; + float item_background_prev_height = 0.0f; float item_background_target_height = 0.0f; TargetSetState target_y_set = TargetSetState::NOT_SET; // TODO: Instead of using this, add functions for modifying |items| and apply the filter on those new items DirtyState items_dirty = DirtyState::FALSE; std::string current_filter; bool using_filter = false; + sf::Shader *rounded_rectangle_mask_shader; }; }
\ No newline at end of file diff --git a/include/QuickMedia.hpp b/include/QuickMedia.hpp index 82b2ee4..09b0806 100644 --- a/include/QuickMedia.hpp +++ b/include/QuickMedia.hpp @@ -79,7 +79,7 @@ namespace QuickMedia { ~Program(); int run(int argc, char **argv); - std::unique_ptr<Body> create_body(); + std::unique_ptr<Body> create_body(bool plain_text_list = false); std::unique_ptr<SearchBar> create_search_bar(const std::string &placeholder, int search_delay); bool load_manga_content_storage(const char *service_name, const std::string &manga_title, const std::string &manga_id); @@ -179,6 +179,7 @@ namespace QuickMedia { std::string resources_root; sf::Shader circle_mask_shader; sf::Shader rounded_rectangle_shader; + sf::Shader rounded_rectangle_mask_shader; bool no_video = false; bool force_no_video = false; bool use_system_mpv_config = false; diff --git a/include/RoundedRectangle.hpp b/include/RoundedRectangle.hpp index 96e57fd..b9d0754 100644 --- a/include/RoundedRectangle.hpp +++ b/include/RoundedRectangle.hpp @@ -17,6 +17,8 @@ namespace QuickMedia { void set_color(sf::Color color); sf::Vector2f get_position() const; sf::Vector2f get_size() const; + void set_band(float y, float height); + void set_band_color(sf::Color color); void draw(sf::RenderTarget &target); private: float radius; @@ -24,5 +26,8 @@ namespace QuickMedia { sf::Vector2f size; sf::Vertex vertices[4]; sf::Shader *rounded_rectangle_shader; + float band_y; + float band_height; + sf::Color band_color; }; }
\ No newline at end of file diff --git a/plugins/Page.hpp b/plugins/Page.hpp index db27fae..6a3ea9f 100644 --- a/plugins/Page.hpp +++ b/plugins/Page.hpp @@ -57,7 +57,7 @@ namespace QuickMedia { // This is called both when first navigating to page and when going back to page virtual void on_navigate_to_page(Body *body) { (void)body; } - std::unique_ptr<Body> create_body(); + std::unique_ptr<Body> create_body(bool plain_text_list = false); std::unique_ptr<SearchBar> create_search_bar(const std::string &placeholder_text, int search_delay); bool load_manga_content_storage(const char *service_name, const std::string &manga_title, const std::string &manga_id); diff --git a/shaders/rounded_rectangle.glsl b/shaders/rounded_rectangle.glsl index 7da0826..2753383 100644 --- a/shaders/rounded_rectangle.glsl +++ b/shaders/rounded_rectangle.glsl @@ -1,4 +1,7 @@ uniform float radius; +uniform float band_y; +uniform float band_height; +uniform vec4 band_color; uniform vec2 resolution; float rounded_rect(vec2 coord, vec2 size, float r) { @@ -11,5 +14,8 @@ void main() { vec2 size = resolution * 0.5; vec4 background_color = vec4(0.0, 0.0, 0.0, 0.0); float a = clamp(rounded_rect(uv - center, size - radius, radius), 0.0, 1.0); - gl_FragColor = mix(gl_Color, background_color, a); + vec4 front_color = gl_Color; + if(uv.y >= band_y && uv.y <= band_y + band_height) + front_color = band_color; + gl_FragColor = mix(front_color, background_color, a); }
\ No newline at end of file diff --git a/shaders/rounded_rectangle_mask.glsl b/shaders/rounded_rectangle_mask.glsl new file mode 100644 index 0000000..4725273 --- /dev/null +++ b/shaders/rounded_rectangle_mask.glsl @@ -0,0 +1,17 @@ +uniform sampler2D texture; +uniform float radius; +uniform vec2 resolution; + +float rounded_rect(vec2 coord, vec2 size, float r) { + return length(max(abs(coord) - size, 0.0)) - r; +} + +void main() { + vec2 uv = gl_TexCoord[0].xy * resolution; + vec2 center = resolution * 0.5; + vec2 size = resolution * 0.5; + vec4 background_color = vec4(0.0, 0.0, 0.0, 0.0); + vec4 texture_color = texture2D(texture, gl_TexCoord[0].xy); + float a = clamp(rounded_rect(uv - center, size - radius, radius), 0.0, 1.0); + gl_FragColor = mix(texture_color, background_color, a); +}
\ No newline at end of file diff --git a/src/Body.cpp b/src/Body.cpp index 25faa1f..7de5f09 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -12,23 +12,68 @@ #include <cmath> #include <malloc.h> -static const sf::Color front_color(32, 36, 42); -static const sf::Color back_color(33, 35, 37); -static const float spacing_y = std::floor(10.0f * QuickMedia::get_ui_scale()); -static const float padding_x = std::floor(10.0f * QuickMedia::get_ui_scale()); -static const float image_padding_x = std::floor(5.0f * QuickMedia::get_ui_scale()); -static const float padding_y = std::floor(5.0f * QuickMedia::get_ui_scale()); -static const float embedded_item_padding_y = std::floor(0.0f * QuickMedia::get_ui_scale()); - -static const float reaction_background_padding_x = std::floor(7.0f * QuickMedia::get_ui_scale()); -static const float reaction_background_padding_y = std::floor(3.0f * QuickMedia::get_ui_scale()); -static const float reaction_spacing_x = std::floor(5.0f * QuickMedia::get_ui_scale()); -static const float reaction_padding_y = std::floor(7.0f * QuickMedia::get_ui_scale()); -static const int embedded_item_font_size = std::floor(14 * QuickMedia::get_ui_scale()); +struct BodySpacing { + float spacing_y = 0.0f; + float padding_x = 0.0f; + float image_padding_x = 0.0f; + float padding_y = 0.0f; + float padding_y_text_only = 0.0f; + float embedded_item_padding_y = 0.0f; + float body_padding_horizontal = 0.0f; + float body_padding_vertical = 0.0f; + + float reaction_background_padding_x = 0.0f; + float reaction_background_padding_y = 0.0f; + float reaction_spacing_x = 0.0f; + float reaction_padding_y = 0.0f; + float embedded_item_font_size = 0.0f; +}; + +static BodySpacing body_spacing[2]; +static bool themes_initialized = false; namespace QuickMedia { - static float clamp(float value, float min, float max) { - return std::min(max, std::max(min, value)); + static void init_body_theme_minimal() { + body_spacing[BODY_THEME_MINIMAL].spacing_y = std::floor(10.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].padding_x = std::floor(10.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].image_padding_x = std::floor(5.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].padding_y = std::floor(5.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].padding_y_text_only = std::floor(5.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].embedded_item_padding_y = std::floor(0.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].body_padding_horizontal = std::floor(10.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].body_padding_vertical = std::floor(10.0f * QuickMedia::get_ui_scale()); + + body_spacing[BODY_THEME_MINIMAL].reaction_background_padding_x = std::floor(7.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].reaction_background_padding_y = std::floor(3.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].reaction_spacing_x = std::floor(5.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].reaction_padding_y = std::floor(7.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MINIMAL].embedded_item_font_size = std::floor(14 * QuickMedia::get_ui_scale()); + } + + static void init_body_theme_modern_spacious() { + body_spacing[BODY_THEME_MODERN_SPACIOUS].spacing_y = std::floor(20.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].padding_x = std::floor(20.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].image_padding_x = std::floor(15.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].padding_y = std::floor(15.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].padding_y_text_only = std::floor(7.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].embedded_item_padding_y = std::floor(0.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].body_padding_horizontal = std::floor(20.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].body_padding_vertical = std::floor(20.0f * QuickMedia::get_ui_scale()); + + body_spacing[BODY_THEME_MODERN_SPACIOUS].reaction_background_padding_x = std::floor(7.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].reaction_background_padding_y = std::floor(3.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].reaction_spacing_x = std::floor(5.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].reaction_padding_y = std::floor(7.0f * QuickMedia::get_ui_scale()); + body_spacing[BODY_THEME_MODERN_SPACIOUS].embedded_item_font_size = std::floor(14 * QuickMedia::get_ui_scale()); + } + + static void init_body_themes() { + if(themes_initialized) + return; + + init_body_theme_minimal(); + init_body_theme_modern_spacious(); + themes_initialized = true; } BodyItem::BodyItem(std::string _title) : @@ -104,25 +149,27 @@ namespace QuickMedia { reactions.push_back(std::move(reaction)); } - Body::Body(Program *program, sf::Texture &loading_icon_texture, sf::Shader *rounded_rectangle_shader) : - progress_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14 * get_ui_scale())), - replies_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14 * get_ui_scale())), - embedded_item_load_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), embedded_item_font_size), + Body::Body(BodyTheme body_theme, sf::Texture &loading_icon_texture, sf::Shader *rounded_rectangle_shader, sf::Shader *rounded_rectangle_mask_shader) : draw_thumbnails(true), - line_separator_color(sf::Color(32, 37, 43, 255)), body_item_render_callback(nullptr), thumbnail_mask_shader(nullptr), - program(program), + body_theme(body_theme), selected_item(0), prev_selected_item(0), loading_icon(loading_icon_texture), + progress_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14 * get_ui_scale())), + replies_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14 * get_ui_scale())), num_visible_items(0), top_cut_off(false), bottom_cut_off(false), item_background(sf::Vector2f(1.0f, 1.0f), 10.0f, sf::Color(55, 60, 68), rounded_rectangle_shader), - reaction_background(sf::Vector2f(1.0f, 1.0f), 10.0f, sf::Color(33, 37, 44), rounded_rectangle_shader) + reaction_background(sf::Vector2f(1.0f, 1.0f), 10.0f, sf::Color(33, 37, 44), rounded_rectangle_shader), + rounded_rectangle_mask_shader(rounded_rectangle_mask_shader) { assert(rounded_rectangle_shader); + assert(rounded_rectangle_mask_shader); + init_body_themes(); + embedded_item_load_text = sf::Text("", *FontLoader::get_font(FontLoader::FontType::LATIN), body_spacing[body_theme].embedded_item_font_size); progress_text.setFillColor(sf::Color::White); replies_text.setFillColor(sf::Color(129, 162, 190)); thumbnail_max_size.x = 250; @@ -417,6 +464,19 @@ namespace QuickMedia { return false; } + void Body::draw_drop_shadow(sf::RenderWindow &window) { + if(!show_drop_shadow) + return; + + const float height = 5.0f; + sf::Vertex gradient_points[4]; + gradient_points[0] = sf::Vertex(body_pos + sf::Vector2f(0.0f, 0.0f), sf::Color(21, 25, 30)); + gradient_points[1] = sf::Vertex(body_pos + sf::Vector2f(body_size.x, 0.0f), sf::Color(21, 25, 30)); + gradient_points[2] = sf::Vertex(body_pos + sf::Vector2f(body_size.x, height), sf::Color(0, 0, 0, 0)); + gradient_points[3] = sf::Vertex(body_pos + sf::Vector2f(0.0f, height), sf::Color(0, 0, 0, 0)); + window.draw(gradient_points, 4, sf::Quads); + } + void Body::draw(sf::RenderWindow &window, sf::Vector2f pos, sf::Vector2f size) { draw(window, pos, size, Json::Value::nullSingleton()); } @@ -430,10 +490,20 @@ namespace QuickMedia { items_dirty = DirtyState::FALSE; } + bool body_size_changed = std::abs(size.x - body_size.x) > 0.1f || std::abs(size.y - body_size.y) > 0.1f; + if(body_size_changed) + body_size = size; + body_pos = pos; const float scissor_y = pos.y; pos.y = 0.0f; + pos.x += body_spacing[body_theme].body_padding_horizontal; + if(attach_side == AttachSide::TOP) + pos.y += body_spacing[body_theme].body_padding_vertical; + + size.x = std::max(0.0f, size.x - body_spacing[body_theme].body_padding_horizontal * 2.0f); + float frame_time = frame_timer.restart().asSeconds(); if(frame_time > 0.01666f) frame_time = 0.01666f; @@ -448,10 +518,6 @@ namespace QuickMedia { prev_selected_item = selected_item; } - bool body_size_changed = std::abs(size.x - body_size.x) > 0.1f || std::abs(size.y - body_size.y) > 0.1f; - if(body_size_changed) - body_size = size; - elapsed_time_sec = draw_timer.getElapsedTime().asSeconds(); const int prev_num_visible_items = num_visible_items; @@ -483,6 +549,8 @@ namespace QuickMedia { mouse_left_clicked = false; clicked_body_item = nullptr; + + draw_drop_shadow(window); return; } @@ -540,7 +608,7 @@ namespace QuickMedia { double dist_to_target; if(body_swipe_move_right) - dist_to_target = body_size.x - body_swipe_x; + dist_to_target = (body_size.x - body_spacing[body_theme].body_padding_horizontal) - body_swipe_x; else dist_to_target = 0.0f - body_swipe_x; body_swipe_x += (dist_to_target * std::min(1.0f, frame_time * move_speed)); @@ -553,7 +621,7 @@ namespace QuickMedia { const int selected_prev_item = get_previous_visible_item(selected_item); const bool selected_merge_with_previous = selected_prev_item != -1 && body_item_merge_handler && body_item_merge_handler(items[selected_prev_item].get(), items[selected_item].get()); get_item_height(items[selected_item].get(), size.x, true, true, selected_merge_with_previous, selected_item); - selected_item_fits_in_body = items[selected_item]->last_loaded_height < body_size.y; + selected_item_fits_in_body = items[selected_item]->last_loaded_height < size.y; if(selected_item_fits_in_body) selected_scrolled = 0.0f; @@ -572,24 +640,27 @@ namespace QuickMedia { const float speed = 30.0f; - const float item_background_prev_height = item_background.get_size().y; const float item_background_height_diff = item_background_target_height - item_background_prev_height; const float item_background_height_speed = instant_move ? 1000.0f : speed; const float item_background_new_height = item_background_prev_height + (item_background_height_diff * std::min(1.0f, frame_time * item_background_height_speed)); item_background.set_size(sf::Vector2f(size.x, item_background_new_height)); + item_background_prev_height = item_background_new_height; - const float item_background_prev_pos_y = item_background.get_position().y; const float item_background_pos_diff = item_background_target_pos_y - item_background_prev_pos_y; const float item_background_move_speed = instant_move ? 1000.0f : speed; float item_background_new_pos_y = item_background_prev_pos_y + (item_background_pos_diff * std::min(1.0f, frame_time * item_background_move_speed)); if(selected_item_fits_in_body) { - item_background_new_pos_y = std::min(item_background_new_pos_y, body_size.y - item_background_new_height - spacing_y); + item_background_new_pos_y = std::min(item_background_new_pos_y, size.y - item_background_new_height - body_spacing[body_theme].spacing_y); item_background_new_pos_y = std::max(item_background_new_pos_y, 0.0f); } item_background.set_position(sf::Vector2f(pos.x, item_background_new_pos_y)); + item_background_prev_pos_y = item_background_new_pos_y; - if(prev_num_visible_items > 0 && render_selected_item_bg) + if(prev_num_visible_items > 0 && render_selected_item_bg && body_theme == BODY_THEME_MINIMAL) { + item_background.set_color(sf::Color(55, 60, 68)); + item_background.set_band(0.0f, 0.0f); item_background.draw(window); + } int index; if(attach_side == AttachSide::TOP) { @@ -603,11 +674,11 @@ namespace QuickMedia { } else { if(page_scroll < 0.0) page_scroll = 0.0; - pos.y += body_size.y; + pos.y += size.y; pos.y += page_scroll; index = get_previous_visible_item(num_items); - if(pos.y + selected_scrolled < body_size.y) + if(pos.y + selected_scrolled < size.y) selected_scrolled = 0.0f; } @@ -633,7 +704,7 @@ namespace QuickMedia { const bool merge_with_previous = body_item_merge_handler && body_item_merge_handler(prev_body_item, item); if(attach_side == AttachSide::TOP && merge_with_previous) - pos.y -= spacing_y; + pos.y -= body_spacing[body_theme].spacing_y; get_item_height(item, size.x, false, true, merge_with_previous, index); const float item_height_diff = item->last_loaded_height - item->current_loaded_height; @@ -645,7 +716,7 @@ namespace QuickMedia { if(attach_side == AttachSide::TOP) top_y = pos.y; else - top_y = pos.y - (item->current_loaded_height + spacing_y); + top_y = pos.y - (item->current_loaded_height + body_spacing[body_theme].spacing_y); if(top_y < 0.0f) { top_cut_off = true; @@ -653,30 +724,30 @@ namespace QuickMedia { selected_line_top_visible = false; } - if(top_y + item->current_loaded_height > body_size.y) { + if(top_y + item->current_loaded_height > size.y) { bottom_cut_off = true; if(index == selected_item) selected_line_bottom_visible = false; } - const bool is_item_visible_in_body = top_y + item->current_loaded_height >= 0.0f && top_y <= body_size.y; + const bool is_item_visible_in_body = top_y + item->current_loaded_height >= 0.0f && top_y <= size.y; if(is_item_visible_in_body || index == selected_item) { get_item_height(item, size.x, true, true, merge_with_previous, index); const float item_height_diff = item->last_loaded_height - item->current_loaded_height; const float add_height = item_height_diff * std::min(1.0, frame_time * height_move_speed); item->current_loaded_height += add_height; if(attach_side == AttachSide::BOTTOM) - pos.y -= (item->current_loaded_height + spacing_y); + pos.y -= (item->current_loaded_height + body_spacing[body_theme].spacing_y); //page_scroll += add_height; - //const float top_y_clamped = clamp(pos.y, 0.0f, body_size.y); - //const float bottom_y_clamped = std::min(pos.y + item->current_loaded_height, body_size.y); + //const float top_y_clamped = clamp(pos.y, 0.0f, size.y); + //const float bottom_y_clamped = std::min(pos.y + item->current_loaded_height, size.y); //float offset_y = 0.0f; //if(pos.y < 0.0f) // offset_y = pos.y; - //else if(pos.y > body_size.y) - // offset_y = body_size.y - pos.y; + //else if(pos.y > size.y) + // offset_y = size.y - pos.y; //sf::View new_view(sf::FloatRect(0.0f, 0.0f, window_size.x, scissor_y + bottom_y_clamped)); //new_view.setViewport(sf::FloatRect(0.0f, (scissor_y + top_y_clamped) / (float)window_size.y, 1.0f, (scissor_y + bottom_y_clamped) / (float)window_size.y)); @@ -692,12 +763,12 @@ namespace QuickMedia { last_visible_item = index; if(attach_side == AttachSide::TOP) - pos.y += (item->current_loaded_height + spacing_y); + pos.y += (item->current_loaded_height + body_spacing[body_theme].spacing_y); } else { if(attach_side == AttachSide::TOP) - pos.y += (item->current_loaded_height + spacing_y); + pos.y += (item->current_loaded_height + body_spacing[body_theme].spacing_y); else - pos.y -= (item->current_loaded_height + spacing_y); + pos.y -= (item->current_loaded_height + body_spacing[body_theme].spacing_y); if(item->keep_alive_frames == 0) { clear_body_item_cache(item); @@ -710,7 +781,7 @@ namespace QuickMedia { } if(attach_side == AttachSide::BOTTOM && merge_with_previous) - pos.y += spacing_y; + pos.y += body_spacing[body_theme].spacing_y; if(attach_side == AttachSide::TOP) { prev_body_item = item; @@ -721,17 +792,19 @@ namespace QuickMedia { } window.setView(prev_view); + draw_drop_shadow(window); // TODO: Move up where scroll is limited? then we wont delay this by 1 frame creating a small scroll overflow only in the opposite direction of attach side. // Also take |selected_scrolled| into consideration + // Limit scroll in the opposide direction of attach side, since the scroll is already limited for the attach side above (with a simple check) if(attach_side == AttachSide::TOP) { const float body_total_height = pos.y - pos_y_start; - if(top_cut_off && !bottom_cut_off && body_total_height > body_size.y) - page_scroll = -(body_total_height - body_size.y); + if(top_cut_off && !bottom_cut_off && body_total_height > (size.y - body_spacing[body_theme].body_padding_vertical)) + page_scroll = -(body_total_height - (size.y - body_spacing[body_theme].body_padding_vertical)); } else { const float body_total_height = pos_y_start - pos.y; - if(bottom_cut_off && !top_cut_off && body_total_height > body_size.y) - page_scroll = (body_total_height - body_size.y); + if(bottom_cut_off && !top_cut_off && body_total_height > size.y) + page_scroll = (body_total_height - size.y); } mouse_left_clicked = false; @@ -745,8 +818,8 @@ namespace QuickMedia { if(is_touch_enabled()) return; - const float item_target_top_diff = item_background_target_pos_y - selected_scrolled; - const float item_target_bottom_diff = (item_background_target_pos_y - selected_scrolled + item_background_target_height + spacing_y) - body_size.y; + const float item_target_top_diff = item_background_target_pos_y - selected_scrolled - body_spacing[body_theme].body_padding_vertical; + const float item_target_bottom_diff = (item_background_target_pos_y - selected_scrolled + item_background_target_height + body_spacing[body_theme].spacing_y) - size.y; if(item_target_top_diff < 0.0f || !selected_item_fits_in_body) { //extra_scroll_target -= item_target_top_diff; stuck_direction = StuckDirection::TOP; @@ -900,7 +973,7 @@ namespace QuickMedia { void Body::draw_item(sf::RenderWindow &window, BodyItem *item, sf::Vector2f pos, sf::Vector2f size, bool include_embedded_item, bool is_embedded) { item->keep_alive_frames = 3; get_item_height(item, size.x, true, false, false, -1); - draw_item(window, item, pos, size, size.y + spacing_y, -1, Json::Value::nullSingleton(), include_embedded_item); + draw_item(window, item, pos, size, size.y + body_spacing[body_theme].spacing_y, -1, Json::Value::nullSingleton(), include_embedded_item); } // TODO: Better message? maybe fallback to the reply message, or message status (such as message redacted) @@ -936,6 +1009,18 @@ namespace QuickMedia { } } + static sf::Color interpolate_colors(sf::Color source, sf::Color target, double progress) { + int diff_r = (int)target.r - (int)source.r; + int diff_g = (int)target.g - (int)source.g; + int diff_b = (int)target.b - (int)source.b; + int diff_a = (int)target.a - (int)source.a; + return sf::Color( + source.r + diff_r * progress, + source.g + diff_g * progress, + source.b + diff_b * progress, + source.a + diff_a * progress); + } + void Body::draw_item(sf::RenderWindow &window, BodyItem *item, const sf::Vector2f &pos, const sf::Vector2f &size, const float item_height, const int item_index, const Json::Value &content_progress, bool include_embedded_item, bool merge_with_previous) { sf::Vector2i thumbnail_size = get_item_thumbnail_size(item); std::shared_ptr<ThumbnailData> item_thumbnail; @@ -951,7 +1036,18 @@ namespace QuickMedia { item_pos.x = std::floor(pos.x); item_pos.y = std::floor(pos.y); - float text_offset_x = padding_x; + if(item_index != -1 && body_theme == BODY_THEME_MODERN_SPACIOUS) { + item_background.set_size(sf::Vector2f(size.x, item_height)); + item_background.set_position(item_pos); + item_background.set_color(sf::Color(33, 37, 44)); + item_background.set_band(item_background_prev_pos_y - pos.y, item_background_prev_height); + item_background.set_band_color(sf::Color(55, 60, 68)); + item_background.draw(window); + } + + const float padding_y = item_thumbnail ? body_spacing[body_theme].padding_y : body_spacing[body_theme].padding_y_text_only; + + float text_offset_x = body_spacing[body_theme].padding_x; if(item_thumbnail && !merge_with_previous) { // TODO: Verify if this is safe. The thumbnail is being modified in another thread if(item_thumbnail->loading_state == LoadingState::APPLIED_TO_TEXTURE && item_thumbnail->texture.getNativeHandle() != 0) { @@ -962,14 +1058,18 @@ namespace QuickMedia { auto new_image_size = clamp_to_size(image_size_f, content_size); auto image_scale = get_ratio(image_size_f, new_image_size); image.setScale(image_scale); - image.setPosition(item_pos + sf::Vector2f(image_padding_x, padding_y)); + image.setPosition(item_pos + sf::Vector2f(body_spacing[body_theme].image_padding_x, padding_y)); if(thumbnail_mask_shader && item->thumbnail_mask_type == ThumbnailMaskType::CIRCLE) { thumbnail_mask_shader->setUniform("resolution", new_image_size); window.draw(image, thumbnail_mask_shader); + } else if(rounded_rectangle_mask_shader) { + rounded_rectangle_mask_shader->setUniform("radius", 10.0f); + rounded_rectangle_mask_shader->setUniform("resolution", new_image_size); + window.draw(image, rounded_rectangle_mask_shader); } else { window.draw(image); } - text_offset_x += image_padding_x + new_image_size.x; + text_offset_x += body_spacing[body_theme].image_padding_x + new_image_size.x; // We want the next image fallback to have the same size as the successful image rendering, because its likely the image fallback will have the same size (for example thumbnails on youtube) //image_fallback.setSize(sf::Vector2f(width_ratio * image_size.x, height_ratio * image_size.y)); } else if(!item->thumbnail_url.empty()) { @@ -982,31 +1082,33 @@ namespace QuickMedia { // TODO: Cache circle shape sf::CircleShape circle_shape(content_size.x * 0.5f); circle_shape.setFillColor(fallback_color); - circle_shape.setPosition(item_pos + sf::Vector2f(image_padding_x, padding_y)); + circle_shape.setPosition(item_pos + sf::Vector2f(body_spacing[body_theme].image_padding_x, padding_y)); window.draw(circle_shape); } else { image_fallback.setSize(content_size); image_fallback.setFillColor(fallback_color); - image_fallback.setPosition(item_pos + sf::Vector2f(image_padding_x, padding_y)); + image_fallback.setPosition(item_pos + sf::Vector2f(body_spacing[body_theme].image_padding_x, padding_y)); window.draw(image_fallback); } sf::Vector2f loading_icon_size(loading_icon.getTexture()->getSize().x, loading_icon.getTexture()->getSize().y); auto new_loading_icon_size = clamp_to_size(loading_icon_size, content_size); - loading_icon.setPosition(item_pos + sf::Vector2f(image_padding_x, padding_y) + (content_size * 0.5f)); + loading_icon.setPosition(item_pos + sf::Vector2f(body_spacing[body_theme].image_padding_x, padding_y) + (content_size * 0.5f)); loading_icon.setScale(get_ratio(loading_icon_size, new_loading_icon_size)); loading_icon.setRotation(elapsed_time_sec * 400.0); window.draw(loading_icon); - text_offset_x += image_padding_x + content_size.x; + text_offset_x += body_spacing[body_theme].image_padding_x + content_size.x; } } else if(item->thumbnail_size.x > 0) { - text_offset_x += image_padding_x + thumbnail_size.x; + text_offset_x += body_spacing[body_theme].image_padding_x + thumbnail_size.x; } - const float timestamp_text_y = std::floor(item_pos.y + padding_y - std::floor(6.0f * get_ui_scale())); + const float text_offset_y = std::floor(8.0f * get_ui_scale()); + + const float timestamp_text_y = std::floor(item_pos.y + padding_y - text_offset_y); if(item->author_text && !merge_with_previous) { - item->author_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - 6.0f * get_ui_scale())); - item->author_text->setMaxWidth(size.x - text_offset_x - image_padding_x); + item->author_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - text_offset_y)); + item->author_text->setMaxWidth(size.x - text_offset_x - body_spacing[body_theme].image_padding_x); item->author_text->draw(window); sf::Vector2f replies_text_pos = item->author_text->getPosition() + sf::Vector2f(0.0f, 5.0f); @@ -1027,20 +1129,20 @@ namespace QuickMedia { if(include_embedded_item && item->embedded_item_status != FetchStatus::NONE) { const float border_width = 4.0f; - const float embedded_item_width = std::floor(size.x - text_offset_x - border_width - padding_x); - float embedded_item_height = item->embedded_item ? get_item_height(item->embedded_item.get(), embedded_item_width, true, false) : ((embedded_item_font_size + 5.0f) + embedded_item_padding_y * 2.0f); + const float embedded_item_width = std::floor(size.x - text_offset_x - border_width - body_spacing[body_theme].padding_x); + float embedded_item_height = item->embedded_item ? get_item_height(item->embedded_item.get(), embedded_item_width, true, false) : ((body_spacing[body_theme].embedded_item_font_size + 5.0f) + body_spacing[body_theme].embedded_item_padding_y * 2.0f); sf::RectangleShape border_left(sf::Vector2f(border_width, std::floor(embedded_item_height))); border_left.setFillColor(sf::Color::White); - border_left.setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + 4.0f)); + border_left.setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + body_spacing[body_theme].embedded_item_padding_y + 2.0f)); window.draw(border_left); if(item->embedded_item) { - sf::Vector2f embedded_item_pos(std::floor(item_pos.x + text_offset_x + border_width + padding_x), std::floor(item_pos.y + embedded_item_padding_y + 4.0f)); + sf::Vector2f embedded_item_pos(std::floor(item_pos.x + text_offset_x + border_width + body_spacing[body_theme].padding_x), std::floor(item_pos.y + body_spacing[body_theme].embedded_item_padding_y + 6.0f)); sf::Vector2f embedded_item_size(embedded_item_width, embedded_item_height); draw_item(window, item->embedded_item.get(), embedded_item_pos, embedded_item_size, false, true); } else { embedded_item_load_text.setString(embedded_item_status_to_string(item->embedded_item_status)); - embedded_item_load_text.setPosition(std::floor(item_pos.x + text_offset_x + border_width + padding_x), std::floor(item_pos.y + embedded_item_height * 0.5f - (embedded_item_font_size + 5.0f) * 0.5f + 4.0f)); + embedded_item_load_text.setPosition(std::floor(item_pos.x + text_offset_x + border_width + body_spacing[body_theme].padding_x), std::floor(item_pos.y + embedded_item_height * 0.5f - (body_spacing[body_theme].embedded_item_font_size + 5.0f) * 0.5f + 6.0f)); window.draw(embedded_item_load_text); } item_pos.y += embedded_item_height + 4.0f; @@ -1050,47 +1152,47 @@ namespace QuickMedia { //title_text.setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y)); //window.draw(title_text); if(item->title_text) { - item->title_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - std::floor(6.0f * get_ui_scale()))); - item->title_text->setMaxWidth(size.x - text_offset_x - image_padding_x); + item->title_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - text_offset_y)); + item->title_text->setMaxWidth(size.x - text_offset_x - body_spacing[body_theme].image_padding_x); item->title_text->draw(window); item_pos.y += item->title_text->getHeight() - 2.0f + std::floor(3.0f * get_ui_scale()); } if(item->description_text) { float height_offset = 0.0f; - item->description_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - std::floor(6.0f * get_ui_scale()) + height_offset)); - item->description_text->setMaxWidth(size.x - text_offset_x - image_padding_x); + item->description_text->setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y - text_offset_y) + height_offset); + item->description_text->setMaxWidth(size.x - text_offset_x - body_spacing[body_theme].image_padding_x); item->description_text->draw(window); item_pos.y += item->description_text->getHeight() - 2.0f; } if(!item->reactions.empty() && include_embedded_item) { float reaction_offset_x = 0.0f; - item_pos.y += reaction_padding_y; + item_pos.y += body_spacing[body_theme].reaction_padding_y; float reaction_max_height = 0.0f; // TODO: Fix first row wrap-around for(int i = 0; i < item->reactions.size(); ++i) { auto &reaction = item->reactions[i]; - reaction.text->setMaxWidth(size.x - text_offset_x - image_padding_x); + reaction.text->setMaxWidth(size.x - text_offset_x - body_spacing[body_theme].image_padding_x); reaction.text->updateGeometry(); reaction_max_height = std::max(reaction_max_height, reaction.text->getHeight()); - reaction.text->setPosition(std::floor(item_pos.x + text_offset_x + reaction_offset_x + reaction_background_padding_x), std::floor(item_pos.y + padding_y - 4.0f + reaction_background_padding_y)); + reaction.text->setPosition(std::floor(item_pos.x + text_offset_x + reaction_offset_x + body_spacing[body_theme].reaction_background_padding_x), std::floor(item_pos.y + padding_y - 4.0f + body_spacing[body_theme].reaction_background_padding_y)); reaction_background.set_position(sf::Vector2f(std::floor(item_pos.x + text_offset_x + reaction_offset_x), std::floor(item_pos.y + padding_y))); - reaction_background.set_size(sf::Vector2f(reaction.text->getWidth() + reaction_background_padding_x * 2.0f, reaction.text->getHeight() + reaction_background_padding_y * 2.0f)); + reaction_background.set_size(sf::Vector2f(reaction.text->getWidth() + body_spacing[body_theme].reaction_background_padding_x * 2.0f, reaction.text->getHeight() + body_spacing[body_theme].reaction_background_padding_y * 2.0f)); reaction_background.draw(window); - reaction_offset_x += reaction.text->getWidth() + reaction_background_padding_x * 2.0f + reaction_spacing_x; + reaction_offset_x += reaction.text->getWidth() + body_spacing[body_theme].reaction_background_padding_x * 2.0f + body_spacing[body_theme].reaction_spacing_x; reaction.text->draw(window); - if(text_offset_x + reaction_offset_x + reaction.text->getWidth() + reaction_background_padding_x * 2.0f > size.x && i < (int)item->reactions.size() - 1) { + if(text_offset_x + reaction_offset_x + reaction.text->getWidth() + body_spacing[body_theme].reaction_background_padding_x * 2.0f > size.x && i < (int)item->reactions.size() - 1) { reaction_offset_x = 0.0f; - item_pos.y += reaction.text->getHeight() + reaction_padding_y + std::floor(6.0f * get_ui_scale()); + item_pos.y += reaction.text->getHeight() + body_spacing[body_theme].reaction_padding_y + std::floor(8.0f * get_ui_scale()); reaction_max_height = reaction.text->getHeight(); } } - item_pos.y += reaction_max_height + reaction_padding_y; + item_pos.y += reaction_max_height + body_spacing[body_theme].reaction_padding_y; } if(item_index == selected_item && item->timestamp_text) { - item->timestamp_text->setPosition(std::floor(item_pos.x + size.x - item->timestamp_text->getLocalBounds().width - padding_x), timestamp_text_y + 8.0f); + item->timestamp_text->setPosition(std::floor(item_pos.x + size.x - item->timestamp_text->getLocalBounds().width - body_spacing[body_theme].padding_x), timestamp_text_y + 8.0f); window.draw(*item->timestamp_text); } @@ -1106,7 +1208,7 @@ namespace QuickMedia { if(current_json.isNumeric() && total_json.isNumeric()) { progress_text.setString(std::string("Page: ") + std::to_string(current_json.asInt()) + "/" + std::to_string(total_json.asInt())); auto bounds = progress_text.getLocalBounds(); - progress_text.setPosition(std::floor(item_pos.x + size.x - bounds.width - padding_x), timestamp_text_y + std::floor(6.0f * get_ui_scale())); + progress_text.setPosition(std::floor(item_pos.x + size.x - bounds.width - body_spacing[body_theme].padding_x), timestamp_text_y + std::floor(8.0f * get_ui_scale())); window.draw(progress_text); } } @@ -1116,8 +1218,10 @@ namespace QuickMedia { sf::Vector2i content_size = get_item_thumbnail_size(item); float image_height = 0.0f; - float text_offset_x = padding_x; + float text_offset_x = body_spacing[body_theme].padding_x; + bool has_thumbnail = false; if(draw_thumbnails && load_texture && !item->thumbnail_url.empty() && !merge_with_previous) { + has_thumbnail = true; std::shared_ptr<ThumbnailData> item_thumbnail = AsyncImageLoader::get_instance().get_thumbnail(item->thumbnail_url, item->thumbnail_is_local, content_size); content_size = clamp_to_size_x(content_size, sf::Vector2i(width, content_size.y)); image_height = content_size.y; @@ -1136,19 +1240,19 @@ namespace QuickMedia { sf::Vector2f image_size_f(image_size.x, image_size.y); auto new_image_size = clamp_to_size(image_size_f, to_vec2f(content_size)); image_height = new_image_size.y; - text_offset_x += image_padding_x + new_image_size.x; + text_offset_x += body_spacing[body_theme].image_padding_x + new_image_size.x; } else { - text_offset_x += image_padding_x + content_size.x; + text_offset_x += body_spacing[body_theme].image_padding_x + content_size.x; } } else if(item->thumbnail_size.x > 0) { - text_offset_x += image_padding_x + content_size.x; + text_offset_x += body_spacing[body_theme].image_padding_x + content_size.x; // TODO: Fix. This makes the body item have incorrect position when loading and if the item is merge_with_previous? and has an embedded item //if(!merge_with_previous) // image_height = content_size.y; } if(load_texture) - update_dirty_state(item, width - text_offset_x - image_padding_x); + update_dirty_state(item, width - text_offset_x - body_spacing[body_theme].image_padding_x); float item_height = 0.0f; if(item->title_text) { @@ -1159,9 +1263,9 @@ namespace QuickMedia { } if(include_embedded_item && item->embedded_item_status != FetchStatus::NONE) { if(item->embedded_item) - item_height += (get_item_height(item->embedded_item.get(), width, load_texture, false) + 4.0f + embedded_item_padding_y * 2.0f); + item_height += (get_item_height(item->embedded_item.get(), width, load_texture, false) + 6.0f + body_spacing[body_theme].embedded_item_padding_y * 2.0f); else - item_height += ((embedded_item_font_size + 5.0f) + 4.0f + embedded_item_padding_y * 2.0f); + item_height += ((body_spacing[body_theme].embedded_item_font_size + 5.0f) + 6.0f + body_spacing[body_theme].embedded_item_padding_y * 2.0f); } if(item->description_text) { item_height += item->description_text->getHeight() - 2.0f; @@ -1169,23 +1273,25 @@ namespace QuickMedia { if(!item->reactions.empty() && include_embedded_item) { float reaction_offset_x = 0.0f; - item_height += reaction_padding_y; + item_height += body_spacing[body_theme].reaction_padding_y; float reaction_max_height = 0.0f; for(int i = 0; i < item->reactions.size(); ++i) { auto &reaction = item->reactions[i]; - reaction.text->setMaxWidth(width - text_offset_x - image_padding_x); + reaction.text->setMaxWidth(width - text_offset_x - body_spacing[body_theme].image_padding_x); reaction.text->updateGeometry(); reaction_max_height = std::max(reaction_max_height, reaction.text->getHeight()); - reaction_offset_x += reaction.text->getWidth() + reaction_background_padding_x * 2.0f + reaction_spacing_x; - if(text_offset_x + reaction_offset_x + reaction.text->getWidth() + reaction_background_padding_x * 2.0f > width && i < (int)item->reactions.size() - 1) { + reaction_offset_x += reaction.text->getWidth() + body_spacing[body_theme].reaction_background_padding_x * 2.0f + body_spacing[body_theme].reaction_spacing_x; + if(text_offset_x + reaction_offset_x + reaction.text->getWidth() + body_spacing[body_theme].reaction_background_padding_x * 2.0f > width && i < (int)item->reactions.size() - 1) { reaction_offset_x = 0.0f; - item_height += reaction.text->getHeight() + reaction_padding_y + std::floor(6.0f * get_ui_scale()); + item_height += reaction.text->getHeight() + body_spacing[body_theme].reaction_padding_y + std::floor(8.0f * get_ui_scale()); reaction_max_height = reaction.text->getHeight(); } } - item_height += reaction_max_height + reaction_padding_y; + item_height += reaction_max_height + body_spacing[body_theme].reaction_padding_y; } + const float padding_y = has_thumbnail ? body_spacing[body_theme].padding_y : body_spacing[body_theme].padding_y_text_only; + item_height = std::max(item_height, image_height); item_height += (padding_y * 2.0f); @@ -1208,10 +1314,6 @@ namespace QuickMedia { return item_height; } - float Body::get_spacing_y() const { - return spacing_y; - } - // TODO: Support utf-8 case insensitive find static bool string_find_fuzzy_case_insensitive(const std::string &str, const std::string &substr) { if(str.empty()) return false; diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 42b7106..c9094e3 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -149,6 +149,7 @@ static int get_monitor_max_hz(Display *display) { static int get_largest_monitor_height(Display *display) { int max_height = 0; + for_each_active_monitor_output(display, [&max_height](const XRRCrtcInfo *crtc_info, const XRRModeInfo*) { // Need to get the min of width or height because we want to get the smallest size for monitors in portrait mode, for mobile devices such as pinephone int width_or_height = std::min((int)crtc_info->width, (int)crtc_info->height); @@ -156,8 +157,9 @@ static int get_largest_monitor_height(Display *display) { }); if(max_height == 0) - return DefaultScreenOfDisplay(display)->height; - return std::max(max_height, 480); + max_height = DefaultScreenOfDisplay(display)->height; + + return std::max(max_height, 240); } static void get_screen_resolution(Display *display, int *width, int *height) { @@ -587,8 +589,10 @@ namespace QuickMedia { void Program::init(Window parent_window, std::string &program_path) { disp = XOpenDisplay(NULL); - if (!disp) - throw std::runtime_error("Failed to open display to X11 server"); + if (!disp) { + fprintf(stderr, "Failed to open display to X11 server\n"); + abort(); + } XSetErrorHandler(x_error_handler); XSetIOErrorHandler(x_io_error_handler); @@ -610,8 +614,10 @@ namespace QuickMedia { InputOutput, DefaultVisual(disp, screen), 0, nullptr); - if(!x11_window) - throw std::runtime_error("Failed to create window"); + if(!x11_window) { + fprintf(stderr, "Failed to create window\n"); + abort(); + } if(strcmp(plugin_name, "download") == 0) { XSizeHints *size_hints = XAllocSizeHints(); @@ -656,6 +662,11 @@ namespace QuickMedia { fprintf(stderr, "Failed to load %s/shaders/rounded_rectangle.glsl\n", resources_root.c_str()); abort(); } + + if(!rounded_rectangle_mask_shader.loadFromFile(resources_root + "shaders/rounded_rectangle_mask.glsl", sf::Shader::Type::Fragment)) { + fprintf(stderr, "Failed to load %s/shaders/rounded_rectangle_mask.glsl\n", resources_root.c_str()); + abort(); + } } if(!loading_icon.loadFromFile(resources_root + "images/loading_icon.png")) { @@ -691,14 +702,20 @@ namespace QuickMedia { */ fprintf(stderr, "Monitor hz: %d\n", monitor_hz); - if(create_directory_recursive(get_cache_dir().join("media")) != 0) - throw std::runtime_error("Failed to create media directory"); + if(create_directory_recursive(get_cache_dir().join("media")) != 0) { + fprintf(stderr, "Failed to create media directory\n"); + abort(); + } - if(create_directory_recursive(get_cache_dir().join("thumbnails")) != 0) - throw std::runtime_error("Failed to create thumbnails directory"); + if(create_directory_recursive(get_cache_dir().join("thumbnails")) != 0) { + fprintf(stderr, "Failed to create thumbnails directory\n"); + abort(); + } - //if(create_directory_recursive(get_storage_dir().join("file-manager")) != 0) - // throw std::runtime_error("Failed to create file-manager directory"); + //if(create_directory_recursive(get_storage_dir().join("file-manager")) != 0) { + // fprintf(stderr, "Failed to create file-manager directory\n"); + // abort(); + //} const char *qm_phone_factor = getenv("QM_PHONE_FACTOR"); if(qm_phone_factor && atoi(qm_phone_factor) == 1) @@ -1387,13 +1404,7 @@ namespace QuickMedia { } static void get_body_dimensions(const sf::Vector2f &window_size, SearchBar *search_bar, sf::Vector2f &body_pos, sf::Vector2f &body_size, bool has_tabs = false) { - float body_padding_horizontal = 10.0f; - float body_padding_vertical = std::floor(10.0f); - float body_width = window_size.x - body_padding_horizontal * 2.0f; - /*if(body_width <= 480.0f) { - body_width = window_size.x; - body_padding_horizontal = 10.0f; - }*/ + const float body_width = window_size.x; float tab_h = Tabs::get_shade_height(); if(!search_bar) @@ -1403,12 +1414,12 @@ namespace QuickMedia { tab_h = 0.0f; float search_bottom = search_bar ? search_bar->getBottomWithoutShadow() : 0.0f; - body_pos = sf::Vector2f(body_padding_horizontal, search_bottom + body_padding_vertical + tab_h); - body_size = sf::Vector2f(body_width, window_size.y - search_bottom - body_padding_vertical - tab_h); + body_pos = sf::Vector2f(0.0f, search_bottom + tab_h); + body_size = sf::Vector2f(body_width, window_size.y - search_bottom - tab_h); } - std::unique_ptr<Body> Program::create_body() { - auto body = std::make_unique<Body>(this, loading_icon, &rounded_rectangle_shader); + std::unique_ptr<Body> Program::create_body(bool plain_text_list) { + auto body = std::make_unique<Body>(plain_text_list ? BODY_THEME_MINIMAL : BODY_THEME_MODERN_SPACIOUS, loading_icon, &rounded_rectangle_shader, &rounded_rectangle_mask_shader); body->thumbnail_mask_shader = &circle_mask_shader; return body; } @@ -1748,6 +1759,7 @@ namespace QuickMedia { current_page = PageType::CHAT; current_chat_room = matrix->get_room_by_id(tmp_matrix_chat_page->room_id); + rooms_page->body->show_drop_shadow = false; while(window.isOpen() && current_chat_room) { auto matrix_chat_page = std::make_unique<MatrixChatPage>(this, current_chat_room->id, rooms_page); bool move_room = chat_page(matrix_chat_page.get(), current_chat_room); @@ -1761,6 +1773,7 @@ namespace QuickMedia { current_chat_room = matrix->get_room_by_id(selected_item->url); } + rooms_page->body->show_drop_shadow = true; room_list_body->body_item_select_callback = [&submit_handler](BodyItem *body_item) { submit_handler(body_item->get_title()); @@ -2213,7 +2226,7 @@ namespace QuickMedia { unsigned long num_items = 0; unsigned long bytes_after = 0; unsigned char *properties = nullptr; - if(XGetWindowProperty(display, window, wm_state_atom, 0, 1024, False, XA_ATOM, &type, &format, &num_items, &bytes_after, &properties) != Success) { + if(XGetWindowProperty(display, window, wm_state_atom, 0, 1024, False, XA_ATOM, &type, &format, &num_items, &bytes_after, &properties) != Success || !properties) { fprintf(stderr, "Failed to get window wm state property\n"); return false; } @@ -3405,7 +3418,7 @@ namespace QuickMedia { bool frame_skip_text_entry = false; comment_input.on_submit_callback = [&frame_skip_text_entry, &comment_input, &post_comment_future, &navigation_stage, &request_new_google_captcha_challenge, &comment_to_post, &captcha_post_id, &captcha_solved_time, &post_comment, &selected_file_for_upload, &thread_page](std::string text) -> bool { - if(text.empty()) + if(text.empty() && selected_file_for_upload.empty()) return false; comment_input.set_editable(false); @@ -3737,19 +3750,13 @@ namespace QuickMedia { comment_input.set_max_width(window_size.x - (logo_padding_x + logo_size.x + chat_input_padding_x + logo_padding_x)); comment_input.set_position(sf::Vector2f(std::floor(logo_padding_x + logo_size.x + chat_input_padding_x), chat_input_padding_y)); - float body_padding_horizontal = 10.0f; - float body_padding_vertical = std::floor(10.0f); - float body_width = window_size.x - body_padding_horizontal * 2.0f; - /*if(body_width <= 480.0f) { - body_width = window_size.x; - body_padding_horizontal = 0.0f; - }*/ + const float body_width = window_size.x; comment_input_shade.setSize(sf::Vector2f(window_size.x, chat_input_height_full)); comment_input_shade.setPosition(0.0f, 0.0f); - body_pos = sf::Vector2f(body_padding_horizontal, comment_input_shade.getSize().y + body_padding_vertical); - body_size = sf::Vector2f(body_width, window_size.y - comment_input_shade.getSize().y - body_padding_vertical); + body_pos = sf::Vector2f(0.0f, comment_input_shade.getSize().y); + body_size = sf::Vector2f(body_width, window_size.y - comment_input_shade.getSize().y); logo_sprite.setPosition(logo_padding_x, chat_input_padding_y); file_to_upload_sprite.setPosition(logo_sprite.getPosition() + sf::Vector2f(0.0f, logo_size.y + logo_file_to_upload_spacing)); @@ -4127,26 +4134,27 @@ namespace QuickMedia { std::vector<ChatTab> tabs; ChatTab pinned_tab; - pinned_tab.body = create_body(); + pinned_tab.body = create_body(true); pinned_tab.body->thumbnail_max_size = CHAT_MESSAGE_THUMBNAIL_MAX_SIZE; pinned_tab.body->attach_side = AttachSide::BOTTOM; - pinned_tab.body->line_separator_color = sf::Color::Transparent; tabs.push_back(std::move(pinned_tab)); ChatTab messages_tab; - messages_tab.body = create_body(); + messages_tab.body = create_body(true); messages_tab.body->thumbnail_max_size = CHAT_MESSAGE_THUMBNAIL_MAX_SIZE; messages_tab.body->attach_side = AttachSide::BOTTOM; - messages_tab.body->line_separator_color = sf::Color::Transparent; tabs.push_back(std::move(messages_tab)); ChatTab users_tab; - users_tab.body = create_body(); + users_tab.body = create_body(true); users_tab.body->thumbnail_max_size = CHAT_MESSAGE_THUMBNAIL_MAX_SIZE; users_tab.body->attach_side = AttachSide::TOP; - users_tab.body->line_separator_color = sf::Color::Transparent; tabs.push_back(std::move(users_tab)); + for(ChatTab &tab : tabs) { + tab.body->show_drop_shadow = false; + } + Tabs ui_tabs(&rounded_rectangle_shader, is_touch_enabled() ? sf::Color::Transparent : back_color); const int PINNED_TAB_INDEX = ui_tabs.add_tab("Pinned messages (0)"); const int MESSAGES_TAB_INDEX = ui_tabs.add_tab("Messages"); @@ -4168,7 +4176,7 @@ namespace QuickMedia { bool setting_read_marker = false; sf::Clock start_typing_timer; - const double typing_timeout_seconds = 3.0; + const double typing_timeout_seconds = 5.0; bool typing = false; MessageQueue<bool> typing_state_queue; @@ -4425,7 +4433,7 @@ namespace QuickMedia { ui_tabs.set_text(PINNED_TAB_INDEX, "Pinned messages (" + std::to_string(tabs[PINNED_TAB_INDEX].body->items.size()) + ")"); }; - Body url_selection_body(this, loading_icon, &rounded_rectangle_shader); + Body url_selection_body(BODY_THEME_MINIMAL, loading_icon, &rounded_rectangle_shader, &rounded_rectangle_mask_shader); std::unordered_set<std::string> fetched_messages_set; auto filter_existing_messages = [&fetched_messages_set](Messages &messages) { @@ -5219,9 +5227,6 @@ namespace QuickMedia { tabs[i].body->on_top_reached = on_top_reached; } - const float body_padding_horizontal = 10.0f; - const float body_padding_vertical = 10.0f; - while (current_page == PageType::CHAT && window.isOpen() && !move_room) { sf::Int32 frame_time_ms = frame_timer.restart().asMilliseconds(); while (window.pollEvent(event)) { @@ -5626,11 +5631,7 @@ namespace QuickMedia { tab_shade_height = std::floor(tab_vertical_offset) + Tabs::get_height() + room_name_padding_y; - float body_width = window_size.x - body_padding_horizontal * 2.0f; - /*if(body_width <= 480.0f) { - body_width = window_size.x; - body_padding_horizontal = 0.0f; - }*/ + const float body_width = window_size.x; this->body_pos = sf::Vector2f(0.0f, tab_shade_height); if(window_size.x > 900.0f && show_room_side_panel) { @@ -5641,19 +5642,19 @@ namespace QuickMedia { draw_room_list = false; } - body_pos = sf::Vector2f(this->body_pos.x + this->body_size.x + body_padding_horizontal, body_padding_vertical + tab_shade_height); - body_size = sf::Vector2f(body_width - this->body_pos.x - this->body_size.x, window_size.y - chat_input_height_full - body_padding_vertical - tab_shade_height); + body_pos = sf::Vector2f(this->body_pos.x + this->body_size.x, tab_shade_height); + body_size = sf::Vector2f(body_width - this->body_pos.x - this->body_size.x, window_size.y - chat_input_height_full - tab_shade_height); - chat_input_shade.setSize(sf::Vector2f(window_size.x - (body_pos.x - body_padding_horizontal), chat_input_height_full)); - chat_input_shade.setPosition(body_pos.x - body_padding_horizontal, window_size.y - chat_input_shade.getSize().y); + chat_input_shade.setSize(sf::Vector2f(window_size.x - body_pos.x, chat_input_height_full)); + chat_input_shade.setPosition(body_pos.x, window_size.y - chat_input_shade.getSize().y); - chat_input.set_max_width(window_size.x - (logo_padding_x + logo_size.x + chat_input_padding_x + logo_padding_x + body_pos.x - body_padding_horizontal)); - chat_input.set_position(sf::Vector2f(std::floor(body_pos.x - body_padding_horizontal + logo_padding_x + logo_size.x + chat_input_padding_x), window_size.y - chat_height - chat_input_padding_y)); + chat_input.set_max_width(window_size.x - (logo_padding_x + logo_size.x + chat_input_padding_x + logo_padding_x + body_pos.x)); + chat_input.set_position(sf::Vector2f(std::floor(body_pos.x + logo_padding_x + logo_size.x + chat_input_padding_x), window_size.y - chat_height - chat_input_padding_y)); more_messages_below_rect.setSize(sf::Vector2f(chat_input_shade.getSize().x, gradient_height)); more_messages_below_rect.setPosition(chat_input_shade.getPosition().x, std::floor(window_size.y - chat_input_height_full - gradient_height)); - logo_sprite.setPosition(body_pos.x - body_padding_horizontal + logo_padding_x, std::floor(window_size.y - chat_input_height_full * 0.5f - logo_size.y * 0.5f)); + logo_sprite.setPosition(body_pos.x + logo_padding_x, std::floor(window_size.y - chat_input_height_full * 0.5f - logo_size.y * 0.5f)); } sync_data.messages.clear(); @@ -5746,14 +5747,12 @@ namespace QuickMedia { } else { tabs[selected_tab].body->draw(window, body_pos, body_size); if(selected_tab == MESSAGES_TAB_INDEX && mention.visible && chat_state == ChatState::TYPING_MESSAGE) { - sf::RectangleShape user_mention_background(sf::Vector2f(body_size.x + body_padding_vertical*2.0f, user_mention_body_height)); - user_mention_background.setPosition(sf::Vector2f(body_pos.x - body_padding_vertical, body_pos.y + body_size.y - user_mention_body_height)); + sf::RectangleShape user_mention_background(sf::Vector2f(body_size.x, user_mention_body_height)); + user_mention_background.setPosition(sf::Vector2f(body_pos.x, body_pos.y + body_size.y - user_mention_body_height)); user_mention_background.setFillColor(sf::Color(33, 37, 44)); window.draw(user_mention_background); - tabs[USERS_TAB_INDEX].body->draw(window, - user_mention_background.getPosition() + sf::Vector2f(body_padding_vertical, body_padding_vertical), - user_mention_background.getSize() - sf::Vector2f(body_padding_vertical*2.0f, body_padding_vertical)); + tabs[USERS_TAB_INDEX].body->draw(window, user_mention_background.getPosition(), user_mention_background.getSize()); } } @@ -5787,9 +5786,8 @@ namespace QuickMedia { glScissor(0.0f, 0.0f, this->body_size.x, window_size.y); window.draw(room_list_background); window.draw(room_label); - const float padding_x = std::floor(10.0f * get_ui_scale()); const float tab_y = std::floor(tab_vertical_offset) + room_name_padding_y; - matrix_chat_page->rooms_page->body->draw(window, sf::Vector2f(padding_x, tab_y), sf::Vector2f(this->body_size.x - padding_x * 2.0f, window_size.y - tab_y), Json::Value::nullSingleton()); + matrix_chat_page->rooms_page->body->draw(window, sf::Vector2f(0.0f, tab_y), sf::Vector2f(this->body_size.x, window_size.y - tab_y), Json::Value::nullSingleton()); glDisable(GL_SCISSOR_TEST); } @@ -5851,8 +5849,8 @@ namespace QuickMedia { window.draw(user_mention_background); tabs[USERS_TAB_INDEX].body->draw(window, - sf::Vector2f(body_pos.x, item_background.getPosition().y - user_mention_body_height + body_padding_vertical), - sf::Vector2f(body_size.x, user_mention_body_height - body_padding_vertical)); + sf::Vector2f(body_pos.x, item_background.getPosition().y - user_mention_body_height), + sf::Vector2f(body_size.x, user_mention_body_height)); } replying_to_text.setPosition(body_item_pos.x, body_item_pos.y - replying_to_text_height); @@ -6028,7 +6026,7 @@ namespace QuickMedia { auto rooms_tags_body = create_body(); auto matrix_rooms_tag_page = std::make_unique<MatrixRoomTagsPage>(this, rooms_tags_body.get()); - auto rooms_body = create_body(); + auto rooms_body = create_body(true); auto rooms_page_search_bar = create_search_bar("Search...", SEARCH_DELAY_FILTER); auto matrix_rooms_page = std::make_unique<MatrixRoomsPage>(this, rooms_body.get(), "All rooms", nullptr, rooms_page_search_bar.get()); @@ -6453,7 +6451,7 @@ namespace QuickMedia { const float loading_bar_padding_x = std::floor(4.0f * get_ui_scale()); const float loading_bar_padding_y = std::floor(4.0f * get_ui_scale()); RoundedRectangle loading_bar_background(sf::Vector2f(1.0f, 1.0f), std::floor(10.0f * get_ui_scale()), sf::Color(21, 25, 30), &rounded_rectangle_shader); - RoundedRectangle loading_bar(sf::Vector2f(1.0f, 1.0f), std::floor(10.0f * get_ui_scale() - loading_bar_padding_y), sf::Color(0, 85, 119), &rounded_rectangle_shader); + RoundedRectangle loading_bar(sf::Vector2f(1.0f, 1.0f), std::floor(10.0f * get_ui_scale() - loading_bar_padding_y), sf::Color(31, 117, 255), &rounded_rectangle_shader); const float padding_x = std::floor(30.0f * get_ui_scale()); const float spacing_y = std::floor(15.0f * get_ui_scale()); @@ -6634,7 +6632,7 @@ namespace QuickMedia { cancel_button.set_background_color(sf::Color(41, 45, 50)); Button save_button("Save", FontLoader::get_font(FontLoader::FontType::LATIN), 16, 100.0f, &rounded_rectangle_shader, get_ui_scale()); - save_button.set_background_color(sf::Color(71, 75, 180)); + save_button.set_background_color(sf::Color(31, 117, 255)); sf::Text file_name_label("File name:", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(16.0f * get_ui_scale())); diff --git a/src/RoundedRectangle.cpp b/src/RoundedRectangle.cpp index 4b06ea8..494a254 100644 --- a/src/RoundedRectangle.cpp +++ b/src/RoundedRectangle.cpp @@ -4,7 +4,9 @@ #include <assert.h> namespace QuickMedia { - RoundedRectangle::RoundedRectangle(sf::Vector2f size, float radius, sf::Color color, sf::Shader *rounded_rectangle_shader) : radius(radius), pos(0.0f, 0.0f), size(size), rounded_rectangle_shader(rounded_rectangle_shader) { + RoundedRectangle::RoundedRectangle(sf::Vector2f size, float radius, sf::Color color, sf::Shader *rounded_rectangle_shader) : + radius(radius), pos(0.0f, 0.0f), size(size), rounded_rectangle_shader(rounded_rectangle_shader), band_y(0.0f), band_height(0.0f), band_color(sf::Color::Transparent) + { assert(rounded_rectangle_shader); vertices[0].color = color; vertices[1].color = color; @@ -45,9 +47,21 @@ namespace QuickMedia { return size; } + void RoundedRectangle::set_band(float y, float height) { + band_y = y; + band_height = height; + } + + void RoundedRectangle::set_band_color(sf::Color color) { + band_color = color; + } + void RoundedRectangle::draw(sf::RenderTarget &target) { - rounded_rectangle_shader->setUniform("resolution", size); rounded_rectangle_shader->setUniform("radius", radius); + rounded_rectangle_shader->setUniform("band_y", band_y); + rounded_rectangle_shader->setUniform("band_height", band_height); + rounded_rectangle_shader->setUniform("band_color", sf::Glsl::Vec4(band_color.r/255.0f, band_color.g/255.0f, band_color.b/255.0f, band_color.a/255.0f)); + rounded_rectangle_shader->setUniform("resolution", size); target.draw(vertices, 4, sf::Quads, rounded_rectangle_shader); } }
\ No newline at end of file diff --git a/src/SearchBar.cpp b/src/SearchBar.cpp index c0a8aad..f7e732a 100644 --- a/src/SearchBar.cpp +++ b/src/SearchBar.cpp @@ -154,7 +154,7 @@ namespace QuickMedia { void SearchBar::onWindowResize(const sf::Vector2f &size) { draw_logo = plugin_logo_sprite.getTexture() != nullptr; - if(size.x * 2.0f < 400.0f) + if(size.x < 400.0f) draw_logo = false; float font_height = text.getCharacterSize() + 7.0f; diff --git a/src/VideoPlayer.cpp b/src/VideoPlayer.cpp index 9dbbe85..8d9bf46 100644 --- a/src/VideoPlayer.cpp +++ b/src/VideoPlayer.cpp @@ -43,8 +43,10 @@ namespace QuickMedia { resource_root(resource_root) { display = XOpenDisplay(NULL); - if (!display) - throw std::runtime_error("Failed to open display to X11 server"); + if (!display) { + fprintf(stderr, "Failed to open display to X11 server\n"); + abort(); + } fprintf(stderr, "Video max height: %d\n", monitor_height); } diff --git a/src/plugins/FileManager.cpp b/src/plugins/FileManager.cpp index 42c2f9e..04e284a 100644 --- a/src/plugins/FileManager.cpp +++ b/src/plugins/FileManager.cpp @@ -34,14 +34,12 @@ namespace QuickMedia { return last_write_time; } - PluginResult FileManagerPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) { - (void)url; - + PluginResult FileManagerPage::submit(const std::string&, const std::string &url, std::vector<Tab> &result_tabs) { std::filesystem::path new_path; - if(title == "..") + if(url == "..") new_path = current_dir.parent_path(); else - new_path = current_dir / title; + new_path = current_dir / url; if(std::filesystem::is_regular_file(new_path)) { program->select_file(new_path); @@ -89,7 +87,8 @@ namespace QuickMedia { }); if(current_dir != "/") { - auto parent_item = BodyItem::create(".."); + auto parent_item = BodyItem::create("Go to parent directory"); + parent_item->url = ".."; result_items.push_back(std::move(parent_item)); } @@ -114,6 +113,7 @@ namespace QuickMedia { continue; auto body_item = BodyItem::create(p.path().filename().string()); + body_item->url = body_item->get_title(); if(file_mime_type == FILE_MANAGER_MIME_TYPE_IMAGE || file_mime_type == FILE_MANAGER_MIME_TYPE_VIDEO) { body_item->thumbnail_is_local = true; body_item->thumbnail_url = p.path().string(); diff --git a/src/plugins/Fourchan.cpp b/src/plugins/Fourchan.cpp index 07b5425..d2f81a9 100644 --- a/src/plugins/Fourchan.cpp +++ b/src/plugins/Fourchan.cpp @@ -167,7 +167,7 @@ namespace QuickMedia { } PluginResult FourchanBoardsPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) { - result_tabs.push_back(Tab{create_body(), std::make_unique<FourchanThreadListPage>(program, title, url), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + result_tabs.push_back(Tab{create_body(false), std::make_unique<FourchanThreadListPage>(program, title, url), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); return PluginResult::OK; } @@ -353,7 +353,7 @@ namespace QuickMedia { ++body_item_index; } - auto body = create_body(); + auto body = create_body(false); body->items = std::move(result_items); result_tabs.push_back(Tab{std::move(body), std::make_unique<FourchanThreadPage>(program, board_id, url), nullptr}); return PluginResult::OK; diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index f9cdab5..1e69bd7 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -728,7 +728,7 @@ namespace QuickMedia { } PluginResult MatrixRoomTagsPage::submit(const std::string&, const std::string &url, std::vector<Tab> &result_tabs) { - auto body = create_body(); + auto body = create_body(true); Body *body_ptr = body.get(); TagData &tag_data = tag_body_items_by_name[url]; body->items = tag_data.room_body_items; @@ -1008,7 +1008,7 @@ namespace QuickMedia { if(strncmp(server_name.c_str(), "www.", 4) == 0) server_name.erase(0, 4); - result_tabs.push_back(Tab{create_body(), std::make_unique<MatrixServerRoomListPage>(program, matrix, server_name), create_search_bar("Search...", 350)}); + result_tabs.push_back(Tab{create_body(), std::make_unique<MatrixServerRoomListPage>(program, matrix, server_name), create_search_bar("Search...", 400)}); return PluginResult::OK; } @@ -2174,6 +2174,11 @@ namespace QuickMedia { message->related_event_type = RelatedEventType::REDACTION; message->transaction_id = std::move(transaction_id); + if(sent_by_somebody_else) { + std::string sender_display_name = extract_first_line_remove_newline_elipses(room_data->get_user_display_name(user_sender), AUTHOR_MAX_LENGTH); + message->body += " by " + sender_display_name; + } + const rapidjson::Value &reason_json = GetMember(*content_json, "reason"); if(reason_json.IsString()) { message->body += ", reason: "; @@ -3871,7 +3876,7 @@ namespace QuickMedia { }; std::string server_response; - DownloadResult download_result = download_to_string(homeserver + "/_matrix/client/r0/join/" + room_id, server_response, std::move(additional_args), true); + DownloadResult download_result = download_to_string(homeserver + "/_matrix/client/r0/join/" + url_param_encode(room_id), server_response, std::move(additional_args), true); if(download_result == DownloadResult::OK) { std::lock_guard<std::mutex> invite_lock(invite_mutex); auto invite_it = invites.find(room_id); @@ -3909,7 +3914,7 @@ namespace QuickMedia { }; std::string server_response; - DownloadResult download_result = download_to_string(homeserver + "/_matrix/client/r0/rooms/" + room_id + "/leave", server_response, std::move(additional_args), true); + DownloadResult download_result = download_to_string(homeserver + "/_matrix/client/r0/rooms/" + url_param_encode(room_id) + "/leave", server_response, std::move(additional_args), true); if(download_result == DownloadResult::OK) { RoomData *room = get_room_by_id(room_id); if(room) { @@ -3991,6 +3996,7 @@ namespace QuickMedia { if(!description.empty()) description += '\n'; description += canonical_alias_json.GetString(); + room_body_item->url = canonical_alias_json.GetString(); } const rapidjson::Value &num_joined_members_json = GetMember(chunk_item_json, "num_joined_members"); diff --git a/src/plugins/Page.cpp b/src/plugins/Page.cpp index 21a33cb..9eb874f 100644 --- a/src/plugins/Page.cpp +++ b/src/plugins/Page.cpp @@ -29,8 +29,8 @@ namespace QuickMedia { return DownloadResult::OK; } - std::unique_ptr<Body> Page::create_body() { - return program->create_body(); + std::unique_ptr<Body> Page::create_body(bool plain_text_list) { + return program->create_body(plain_text_list); } std::unique_ptr<SearchBar> Page::create_search_bar(const std::string &placeholder_text, int search_delay) { diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp index d164bc5..f7b36d6 100644 --- a/src/plugins/Youtube.cpp +++ b/src/plugins/Youtube.cpp @@ -190,7 +190,9 @@ namespace QuickMedia { if(!desc.empty()) desc += '\n'; desc += '\n'; - desc += description_snippet.value(); + std::string description_snippet_stripped = strip(description_snippet.value()); + string_replace_all(description_snippet_stripped, "\n\n", "\n"); + desc += std::move(description_snippet_stripped); } body_item->set_description(std::move(desc)); body_item->set_description_color(sf::Color(179, 179, 179)); @@ -247,7 +249,9 @@ namespace QuickMedia { if(!desc.empty()) desc += '\n'; desc += '\n'; - desc += description.value(); + std::string description_snippet_stripped = strip(description.value()); + string_replace_all(description_snippet_stripped, "\n\n", "\n"); + desc += std::move(description_snippet_stripped); } body_item->set_description(std::move(desc)); body_item->set_description_color(sf::Color(179, 179, 179)); |