From b857a3f149a5445c39102965adf6f402660c61bd Mon Sep 17 00:00:00 2001 From: YuraIz <7516890@gmail.com> Date: Wed, 22 Mar 2023 16:01:50 +0300 Subject: [PATCH 1/4] feat(chat-history): Add linear gradient to outgoing messages --- data/resources/style.css | 4 + src/session/content/message_row/bubble.rs | 93 +++++++++++++++++++++-- 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/data/resources/style.css b/data/resources/style.css index 1c9574c9d..404ad5a22 100644 --- a/data/resources/style.css +++ b/data/resources/style.css @@ -314,6 +314,10 @@ messagereply label.message { color: @window_fg_color; } +messagebubble.outgoing messagereply label.message { + color: currentColor; +} + messagesticker { border-spacing: 6px; } diff --git a/src/session/content/message_row/bubble.rs b/src/session/content/message_row/bubble.rs index 056a30503..71308c9c4 100644 --- a/src/session/content/message_row/bubble.rs +++ b/src/session/content/message_row/bubble.rs @@ -1,14 +1,13 @@ +use adw::prelude::*; +use glib::clone; +use gtk::subclass::prelude::*; +use gtk::{gdk, glib, graphene, gsk, CompositeTemplate}; +use once_cell::sync::Lazy; use std::cell::RefCell; use std::collections::hash_map::DefaultHasher; use std::hash::Hash; use std::hash::Hasher; -use adw::prelude::*; -use gtk::glib; -use gtk::subclass::prelude::*; -use gtk::CompositeTemplate; -use once_cell::sync::Lazy; - use crate::session::content::message_row::MessageIndicators; use crate::session::content::message_row::MessageLabel; use crate::session::content::message_row::MessageReply; @@ -37,6 +36,8 @@ mod imp { using Adw 1; template $MessageBubble { + overflow: hidden; + Overlay overlay { Box { orientation: vertical; @@ -69,6 +70,7 @@ mod imp { pub(crate) struct MessageBubble { pub(super) sender_color_class: RefCell>, pub(super) sender_binding: RefCell>, + pub(super) parent_list_view: RefCell>, #[template_child] pub(super) overlay: TemplateChild, #[template_child] @@ -128,6 +130,45 @@ mod imp { } impl WidgetImpl for MessageBubble { + fn realize(&self) { + self.parent_realize(); + + let widget = self.obj(); + + if let Some(view) = widget.parent_list_view() { + self.parent_list_view.replace(view.downgrade()); + view.vadjustment() + .unwrap() + .connect_value_notify(clone!(@weak widget => move |_| { + widget.queue_draw(); + })); + } + } + + fn snapshot(&self, snapshot: >k::Snapshot) { + let widget = self.obj(); + if widget.has_css_class("outgoing") { + let width = widget.width() as f32; + let height = widget.height() as f32; + + let bounds = graphene::Rect::new(0.0, 0.0, width, height); + let gradient_bounds = widget.gradient_bounds(); + let [first, second] = widget.linear_gradient_colors(); + + snapshot.append_linear_gradient( + &bounds, + &graphene::Point::new(0.0, gradient_bounds.y()), + &graphene::Point::new(0.0, gradient_bounds.height()), + &[ + gsk::ColorStop::new(0.0, first), + gsk::ColorStop::new(1.0, second), + ], + ); + } + + self.parent_snapshot(snapshot); + } + fn measure(&self, orientation: gtk::Orientation, for_size: i32) -> (i32, i32, i32, i32) { // Limit the widget width if orientation == gtk::Orientation::Horizontal { @@ -317,4 +358,44 @@ impl MessageBubble { .set_indicators(Some(imp.indicators.clone())); } } + + fn parent_list_view(&self) -> Option { + let mut parent = self.parent()?; + loop { + match parent.downcast() { + Ok(list_view) => return Some(list_view), + Err(not_list_view) => parent = not_list_view.parent()?, + } + } + } + + fn gradient_bounds(&self) -> graphene::Rect { + if let Some(view) = self.imp().parent_list_view.borrow().upgrade() { + let view_bounds = view.compute_bounds(self.imp().obj().as_ref()).unwrap(); + + graphene::Rect::new( + view_bounds.x(), + view_bounds.y(), + view_bounds.width() + view_bounds.x(), + view_bounds.height() + view_bounds.y(), + ) + } else { + panic!("can't get parent ListView"); + } + } + + fn linear_gradient_colors(&self) -> [gdk::RGBA; 2] { + // default colors from iOS + if !adw::StyleManager::default().is_dark() { + [ + gdk::RGBA::new(0.91764706, 0.9882353, 0.8235294, 1.0), + gdk::RGBA::new(0.91764706, 0.9882353, 0.8235294, 1.0), + ] + } else { + [ + gdk::RGBA::new(0.21960784, 0.32156864, 0.89411765, 1.0), + gdk::RGBA::new(0.63529414, 0.3372549, 0.58431375, 1.0), + ] + } + } } From 6a2f973ead889aff3091663f63c37ed22982e625 Mon Sep 17 00:00:00 2001 From: YuraIz <7516890@gmail.com> Date: Sat, 20 May 2023 19:18:06 +0300 Subject: [PATCH 2/4] feat(chat-history): Make message gradient 4-color --- src/session/content/background.rs | 140 +++++++++++++++------- src/session/content/message_row/bubble.rs | 90 +++++--------- 2 files changed, 131 insertions(+), 99 deletions(-) diff --git a/src/session/content/background.rs b/src/session/content/background.rs index 713ca213a..85af4ecf7 100644 --- a/src/session/content/background.rs +++ b/src/session/content/background.rs @@ -55,7 +55,9 @@ mod imp { #[derive(Default)] pub(crate) struct Background { - pub(super) gradient_texture: RefCell>, + pub(super) background_texture: RefCell>, + pub(super) message_texture: RefCell>, + pub(super) last_size: Cell<(f32, f32)>, pub(super) shader: RefCell>, @@ -67,7 +69,8 @@ mod imp { pub(super) dark: Cell, - pub(super) colors: RefCell>, + pub(super) bg_colors: RefCell>, + pub(super) message_colors: RefCell>, } #[glib::object_subclass] @@ -108,7 +111,7 @@ mod imp { let target = adw::CallbackAnimationTarget::new(clone!(@weak obj => move |progress| { let imp = obj.imp(); - imp.gradient_texture.take(); + imp.background_texture.take(); let progress = progress as f32; if progress >= 1.0 { imp.progress.set(0.0); @@ -177,18 +180,20 @@ mod imp { size_changed: bool, ) { if self.progress.get() == 0.0 { - let texture = match self.gradient_texture.take() { + let texture = match self.background_texture.take() { Some(texture) if !size_changed => texture, _ => { - let renderer = self.obj().native().unwrap().renderer(); - renderer.render_texture(self.gradient_shader_node(bounds), Some(bounds)) + self.render_textures(bounds); + self.background_texture.take().unwrap() } }; snapshot.append_texture(&texture, bounds); - self.gradient_texture.replace(Some(texture)); + self.background_texture.replace(Some(texture)); } else { - snapshot.append_node(self.gradient_shader_node(bounds)); + self.render_textures(bounds); + let texture = self.background_texture.borrow().as_ref().unwrap().clone(); + snapshot.append_texture(&texture, bounds); } } @@ -226,7 +231,24 @@ mod imp { } } - fn gradient_shader_node(&self, bounds: &graphene::Rect) -> gsk::GLShaderNode { + fn render_textures(&self, bounds: &graphene::Rect) { + let colors = [self.bg_colors.borrow(), self.message_colors.borrow()]; + + let renderer = self.obj().native().unwrap().renderer(); + + let mut textures = colors.into_iter().map(|colors| { + renderer.render_texture(self.gradient_shader_node(bounds, &colors), Some(bounds)) + }); + + self.background_texture.replace(textures.next()); + self.message_texture.replace(textures.next()); + } + + fn gradient_shader_node( + &self, + bounds: &graphene::Rect, + colors: &[graphene::Vec3], + ) -> gsk::GLShaderNode { let Some(gradient_shader) = &*self.shader.borrow() else { unreachable!() }; @@ -236,10 +258,8 @@ mod imp { let progress = self.progress.get(); let phase = self.phase.get() as usize; - let colors = self.colors.borrow(); - - let &[c1, c2, c3, c4] = &colors[..] else { - unimplemented!("Unexpected color count"); + let &[c1, c2, c3, c4] = colors else { + unimplemented!("Unexpected color count") }; args_builder.set_vec3(0, &c1); @@ -305,7 +325,7 @@ impl Background { imp.dark.set(background.is_dark); - let fill = match background.r#type { + let bg_fill = match background.r#type { tdlib::enums::BackgroundType::Pattern(pattern) => pattern.fill, tdlib::enums::BackgroundType::Fill(fill) => fill.fill, tdlib::enums::BackgroundType::Wallpaper(_) => { @@ -313,30 +333,11 @@ impl Background { } }; - match fill { - tdlib::enums::BackgroundFill::FreeformGradient(gradient) => { - if gradient.colors.len() != 4 { - unimplemented!("Unsupported gradient colors count"); - } - - let colors = gradient - .colors - .into_iter() - .map(|int_color| { - let r = (int_color >> 16) & 0xFF; - let g = (int_color >> 8) & 0xFF; - let b = int_color & 0xFF; + imp.bg_colors.replace(fill_colors(bg_fill)); + imp.message_colors + .replace(fill_colors(theme.outgoing_message_fill)); - graphene::Vec3::new(r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0) - }) - .collect(); - - imp.colors.replace(colors); - } - _ => unimplemented!("Background fill"), - } - - imp.gradient_texture.take(); + imp.background_texture.take(); self.queue_draw(); } @@ -349,6 +350,29 @@ impl Background { } } + pub fn subscribe_to_redraw(&self, child: >k::Widget) { + let animation = self.imp().animation.get().unwrap(); + animation.connect_value_notify(clone!(@weak child => move |_| child.queue_draw())); + } + + pub fn bg_texture(&self) -> gdk::Texture { + self.imp() + .background_texture + .borrow() + .as_ref() + .unwrap() + .clone() + } + + pub fn message_texture(&self) -> gdk::Texture { + self.imp() + .message_texture + .borrow() + .as_ref() + .unwrap() + .clone() + } + fn ensure_shader(&self) { let imp = self.imp(); if imp.shader.borrow().is_none() { @@ -376,8 +400,28 @@ impl Default for Background { } } +fn fill_colors(fill: tdlib::enums::BackgroundFill) -> Vec { + match fill { + tdlib::enums::BackgroundFill::FreeformGradient(gradient) if gradient.colors.len() == 4 => { + gradient + .colors + .into_iter() + .map(|int_color| { + let [_, r, g, b] = int_color.to_be_bytes(); + graphene::Vec3::new(r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0) + }) + .collect() + } + _ => unimplemented!("Unsupported background fill: {fill:?}"), + } +} + fn hard_coded_themes(dark: bool) -> tdlib::types::ThemeSettings { - fn theme(dark: bool, colors: Vec) -> tdlib::types::ThemeSettings { + fn theme( + dark: bool, + bg_colors: Vec, + message_colors: Vec, + ) -> tdlib::types::ThemeSettings { use tdlib::enums::BackgroundFill::*; use tdlib::enums::BackgroundType::Fill; use tdlib::types::*; @@ -387,7 +431,7 @@ fn hard_coded_themes(dark: bool) -> tdlib::types::ThemeSettings { is_default: true, is_dark: dark, r#type: Fill(BackgroundTypeFill { - fill: FreeformGradient(BackgroundFillFreeformGradient { colors }), + fill: FreeformGradient(BackgroundFillFreeformGradient { colors: bg_colors }), }), id: 0, name: String::new(), @@ -396,13 +440,25 @@ fn hard_coded_themes(dark: bool) -> tdlib::types::ThemeSettings { accent_color: 0, animate_outgoing_message_fill: false, outgoing_message_accent_color: 0, - outgoing_message_fill: Solid(BackgroundFillSolid { color: 0 }), + outgoing_message_fill: FreeformGradient(BackgroundFillFreeformGradient { + colors: message_colors, + }), } } + // tr tl bl br + if dark { - theme(dark, vec![0xd6932e, 0xbc40db, 0x4280d7, 0x614ed5]) + theme( + dark, + vec![0xd6932e, 0xbc40db, 0x4280d7, 0x614ed5], + vec![0xfc27a6, 0xff9201, 0x7827ff, 0x554efe], + ) } else { - theme(dark, vec![0x94dae9, 0x9aeddb, 0x94c3f6, 0xac96f7]) + theme( + dark, + vec![0x94dae9, 0x9aeddb, 0x94c3f6, 0xac96f7], + vec![0xddffdf, 0xfff0dd, 0xffddfc, 0xddecff], + ) } } diff --git a/src/session/content/message_row/bubble.rs b/src/session/content/message_row/bubble.rs index 71308c9c4..0387c8b77 100644 --- a/src/session/content/message_row/bubble.rs +++ b/src/session/content/message_row/bubble.rs @@ -1,13 +1,19 @@ -use adw::prelude::*; -use glib::clone; -use gtk::subclass::prelude::*; -use gtk::{gdk, glib, graphene, gsk, CompositeTemplate}; -use once_cell::sync::Lazy; use std::cell::RefCell; use std::collections::hash_map::DefaultHasher; use std::hash::Hash; use std::hash::Hasher; +use adw::prelude::*; +use glib::clone; +use gtk::gdk; +use gtk::glib; +use gtk::graphene; +use gtk::gsk; +use gtk::subclass::prelude::*; +use gtk::CompositeTemplate; +use once_cell::sync::Lazy; + +use crate::session::content::background::Background; use crate::session::content::message_row::MessageIndicators; use crate::session::content::message_row::MessageLabel; use crate::session::content::message_row::MessageReply; @@ -71,6 +77,7 @@ mod imp { pub(super) sender_color_class: RefCell>, pub(super) sender_binding: RefCell>, pub(super) parent_list_view: RefCell>, + pub(super) parent_background: RefCell>, #[template_child] pub(super) overlay: TemplateChild, #[template_child] @@ -143,27 +150,28 @@ mod imp { widget.queue_draw(); })); } + + if let Some(background) = widget.parent_background() { + self.parent_background.replace(background.downgrade()); + background.subscribe_to_redraw(widget.upcast_ref()); + } } fn snapshot(&self, snapshot: >k::Snapshot) { let widget = self.obj(); - if widget.has_css_class("outgoing") { - let width = widget.width() as f32; - let height = widget.height() as f32; - - let bounds = graphene::Rect::new(0.0, 0.0, width, height); - let gradient_bounds = widget.gradient_bounds(); - let [first, second] = widget.linear_gradient_colors(); - - snapshot.append_linear_gradient( - &bounds, - &graphene::Point::new(0.0, gradient_bounds.y()), - &graphene::Point::new(0.0, gradient_bounds.height()), - &[ - gsk::ColorStop::new(0.0, first), - gsk::ColorStop::new(1.0, second), - ], - ); + + if let Some(background) = self.parent_background.borrow().upgrade() { + if !background.has_css_class("fallback") { + let gradient_bounds = background.compute_bounds(self.obj().as_ref()).unwrap(); + + if widget.has_css_class("outgoing") { + snapshot.append_texture(&background.message_texture(), &gradient_bounds); + } else { + snapshot.push_opacity(0.1); + snapshot.append_texture(&background.bg_texture(), &gradient_bounds); + snapshot.pop(); + }; + } } self.parent_snapshot(snapshot); @@ -360,42 +368,10 @@ impl MessageBubble { } fn parent_list_view(&self) -> Option { - let mut parent = self.parent()?; - loop { - match parent.downcast() { - Ok(list_view) => return Some(list_view), - Err(not_list_view) => parent = not_list_view.parent()?, - } - } + self.ancestor(gtk::ListView::static_type())?.downcast().ok() } - fn gradient_bounds(&self) -> graphene::Rect { - if let Some(view) = self.imp().parent_list_view.borrow().upgrade() { - let view_bounds = view.compute_bounds(self.imp().obj().as_ref()).unwrap(); - - graphene::Rect::new( - view_bounds.x(), - view_bounds.y(), - view_bounds.width() + view_bounds.x(), - view_bounds.height() + view_bounds.y(), - ) - } else { - panic!("can't get parent ListView"); - } - } - - fn linear_gradient_colors(&self) -> [gdk::RGBA; 2] { - // default colors from iOS - if !adw::StyleManager::default().is_dark() { - [ - gdk::RGBA::new(0.91764706, 0.9882353, 0.8235294, 1.0), - gdk::RGBA::new(0.91764706, 0.9882353, 0.8235294, 1.0), - ] - } else { - [ - gdk::RGBA::new(0.21960784, 0.32156864, 0.89411765, 1.0), - gdk::RGBA::new(0.63529414, 0.3372549, 0.58431375, 1.0), - ] - } + fn parent_background(&self) -> Option { + self.ancestor(Background::static_type())?.downcast().ok() } } From c5da2771b6aa08dd0800c2b3c9af8ce4e556df50 Mon Sep 17 00:00:00 2001 From: YuraIz <7516890@gmail.com> Date: Sun, 11 Jun 2023 10:28:00 +0300 Subject: [PATCH 3/4] feat(chat-history): Update message colors --- src/session/content/background.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/session/content/background.rs b/src/session/content/background.rs index 85af4ecf7..e7b4dcd7e 100644 --- a/src/session/content/background.rs +++ b/src/session/content/background.rs @@ -452,13 +452,13 @@ fn hard_coded_themes(dark: bool) -> tdlib::types::ThemeSettings { theme( dark, vec![0xd6932e, 0xbc40db, 0x4280d7, 0x614ed5], - vec![0xfc27a6, 0xff9201, 0x7827ff, 0x554efe], + vec![0x2d52ab, 0x4036a1, 0x9f388d, 0x9d3941], ) } else { theme( dark, vec![0x94dae9, 0x9aeddb, 0x94c3f6, 0xac96f7], - vec![0xddffdf, 0xfff0dd, 0xffddfc, 0xddecff], + vec![0xddecff, 0xe0ddfd, 0xdbffff, 0xddffdf], ) } } From 2db8736767d798a3a2ba7129357b5914e77d6332 Mon Sep 17 00:00:00 2001 From: YuraIz <7516890@gmail.com> Date: Sun, 11 Jun 2023 11:43:29 +0300 Subject: [PATCH 4/4] perf(chat-history): Render the shader directly to bubbles Rendering big texture into a lot of small bubbles results into bad performance (30fps on my laptop while scrolling). Rendering the shader to small bubbles fixes that issue. --- src/session/content/background.rs | 105 ++++++++++++---------- src/session/content/message_row/bubble.rs | 15 ++-- 2 files changed, 68 insertions(+), 52 deletions(-) diff --git a/src/session/content/background.rs b/src/session/content/background.rs index e7b4dcd7e..aee64972d 100644 --- a/src/session/content/background.rs +++ b/src/session/content/background.rs @@ -21,15 +21,20 @@ uniform vec3 color1; uniform vec3 color2; uniform vec3 color3; uniform vec3 color4; -uniform vec2 p1; -uniform vec2 p2; -uniform vec2 p3; -uniform vec2 p4; +uniform vec4 p12; +uniform vec4 p34; +uniform vec4 gradient_bounds; void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv) { + vec2 p1 = p12.xy; + vec2 p2 = p12.zw; + vec2 p3 = p34.xy; + vec2 p4 = p34.zw; + + uv = (fragCoord - gradient_bounds.xy) / gradient_bounds.zw; uv.y = 1.0 - uv.y; float dp1 = distance(uv, p1); @@ -56,7 +61,6 @@ mod imp { #[derive(Default)] pub(crate) struct Background { pub(super) background_texture: RefCell>, - pub(super) message_texture: RefCell>, pub(super) last_size: Cell<(f32, f32)>, @@ -183,17 +187,16 @@ mod imp { let texture = match self.background_texture.take() { Some(texture) if !size_changed => texture, _ => { - self.render_textures(bounds); - self.background_texture.take().unwrap() + let renderer = self.obj().native().unwrap().renderer(); + + renderer.render_texture(self.obj().bg_node(bounds, bounds), Some(bounds)) } }; snapshot.append_texture(&texture, bounds); self.background_texture.replace(Some(texture)); } else { - self.render_textures(bounds); - let texture = self.background_texture.borrow().as_ref().unwrap().clone(); - snapshot.append_texture(&texture, bounds); + snapshot.append_node(&self.obj().bg_node(bounds, bounds)); } } @@ -231,22 +234,10 @@ mod imp { } } - fn render_textures(&self, bounds: &graphene::Rect) { - let colors = [self.bg_colors.borrow(), self.message_colors.borrow()]; - - let renderer = self.obj().native().unwrap().renderer(); - - let mut textures = colors.into_iter().map(|colors| { - renderer.render_texture(self.gradient_shader_node(bounds, &colors), Some(bounds)) - }); - - self.background_texture.replace(textures.next()); - self.message_texture.replace(textures.next()); - } - - fn gradient_shader_node( + pub(super) fn gradient_shader_node( &self, bounds: &graphene::Rect, + gradient_bounds: &graphene::Rect, colors: &[graphene::Vec3], ) -> gsk::GLShaderNode { let Some(gradient_shader) = &*self.shader.borrow() else { @@ -267,16 +258,25 @@ mod imp { args_builder.set_vec3(2, &c3); args_builder.set_vec3(3, &c4); - let [p1, p2, p3, p4] = Self::calculate_positions(progress, phase); - args_builder.set_vec2(4, &p1); - args_builder.set_vec2(5, &p2); - args_builder.set_vec2(6, &p3); - args_builder.set_vec2(7, &p4); + let [p12, p34] = Self::calculate_positions(progress, phase); + args_builder.set_vec4(4, &p12); + args_builder.set_vec4(5, &p34); + + let gradient_bounds = { + graphene::Vec4::new( + gradient_bounds.x(), + gradient_bounds.y(), + gradient_bounds.width(), + gradient_bounds.height(), + ) + }; + + args_builder.set_vec4(6, &gradient_bounds); gsk::GLShaderNode::new(gradient_shader, bounds, &args_builder.to_args(), &[]) } - fn calculate_positions(progress: f32, phase: usize) -> [graphene::Vec2; 4] { + fn calculate_positions(progress: f32, phase: usize) -> [graphene::Vec4; 2] { static POSITIONS: [(f32, f32); 8] = [ (0.80, 0.10), (0.60, 0.20), @@ -288,7 +288,7 @@ mod imp { (0.75, 0.40), ]; - let mut points = [graphene::Vec2::new(0.0, 0.0); 4]; + let mut points = [(0.0, 0.0); 4]; for i in 0..4 { let start = POSITIONS[(i * 2 + phase) % 8]; @@ -301,10 +301,18 @@ mod imp { let x = interpolate(start.0, end.0, progress); let y = interpolate(start.1, end.1, progress); - points[i] = graphene::Vec2::new(x, y); + points[i] = (x, y); } - points + let points: Vec<_> = points + .chunks(2) + .map(|p| { + let [(x1, y1), (x2, y2)]: [(f32, f32); 2] = p.try_into().unwrap(); + graphene::Vec4::from_float([x1, y1, x2, y2]) + }) + .collect(); + + points.try_into().unwrap() } } } @@ -350,27 +358,30 @@ impl Background { } } - pub fn subscribe_to_redraw(&self, child: >k::Widget) { + pub(crate) fn subscribe_to_redraw(&self, child: >k::Widget) { let animation = self.imp().animation.get().unwrap(); animation.connect_value_notify(clone!(@weak child => move |_| child.queue_draw())); } - pub fn bg_texture(&self) -> gdk::Texture { + pub(crate) fn bg_node( + &self, + bounds: &graphene::Rect, + gradient_bounds: &graphene::Rect, + ) -> gsk::GLShaderNode { self.imp() - .background_texture - .borrow() - .as_ref() - .unwrap() - .clone() + .gradient_shader_node(bounds, gradient_bounds, &self.imp().bg_colors.borrow()) } - pub fn message_texture(&self) -> gdk::Texture { - self.imp() - .message_texture - .borrow() - .as_ref() - .unwrap() - .clone() + pub(crate) fn message_bg_node( + &self, + bounds: &graphene::Rect, + gradient_bounds: &graphene::Rect, + ) -> gsk::GLShaderNode { + self.imp().gradient_shader_node( + bounds, + gradient_bounds, + &self.imp().message_colors.borrow(), + ) } fn ensure_shader(&self) { diff --git a/src/session/content/message_row/bubble.rs b/src/session/content/message_row/bubble.rs index 0387c8b77..b3b4ed550 100644 --- a/src/session/content/message_row/bubble.rs +++ b/src/session/content/message_row/bubble.rs @@ -5,10 +5,7 @@ use std::hash::Hasher; use adw::prelude::*; use glib::clone; -use gtk::gdk; use gtk::glib; -use gtk::graphene; -use gtk::gsk; use gtk::subclass::prelude::*; use gtk::CompositeTemplate; use once_cell::sync::Lazy; @@ -162,13 +159,21 @@ mod imp { if let Some(background) = self.parent_background.borrow().upgrade() { if !background.has_css_class("fallback") { + let bounds = { + let width = widget.width() as f32; + let height = widget.height() as f32; + + gtk::graphene::Rect::new(0.0, 0.0, width, height) + }; + let gradient_bounds = background.compute_bounds(self.obj().as_ref()).unwrap(); if widget.has_css_class("outgoing") { - snapshot.append_texture(&background.message_texture(), &gradient_bounds); + snapshot + .append_node(&background.message_bg_node(&bounds, &gradient_bounds)); } else { snapshot.push_opacity(0.1); - snapshot.append_texture(&background.bg_texture(), &gradient_bounds); + snapshot.append_node(&background.bg_node(&bounds, &gradient_bounds)); snapshot.pop(); }; }