mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-06 21:34:00 -05:00
app/chatview: migrate FileMessage to text2 API
This commit is contained in:
@@ -22,7 +22,7 @@ DEBUG_FEATURES = --features=enable-filelog,enable-plugins
|
||||
|
||||
#DEV_FEATURES = --features=enable-filelog,enable-netdebug,emulate-android
|
||||
#DEV_FEATURES = --features=enable-filelog,enable-netdebug,enable-plugins
|
||||
DEV_FEATURES = --no-default-features --features=schema-app
|
||||
DEV_FEATURES = --features=schema-app
|
||||
|
||||
default: build-release
|
||||
./darkfi-app
|
||||
@@ -88,7 +88,7 @@ dev: $(SRC) fonts assets/forest_1920x1080.ivf
|
||||
|
||||
# Users should use the android-release and android-debug targets instead.
|
||||
apk: $(SRC) fonts assets/forest_720x1280.mp4
|
||||
cargo quad-apk build $(DEV_FEATURES)
|
||||
cargo quad-apk build --no-default-features $(DEV_FEATURES)
|
||||
$(MAKE) install-apk
|
||||
|
||||
install-apk:
|
||||
|
||||
@@ -76,7 +76,7 @@ mod android_ui_consts {
|
||||
pub const SENDARROW_NEG_X: f32 = 80.;
|
||||
pub const SENDARROW_NEG_Y: f32 = 80.;
|
||||
pub const SENDBTN_BOX: [f32; 4] = [116., 120., 80., 70.];
|
||||
pub const FONTSIZE: f32 = 40.;
|
||||
pub const FONTSIZE: f32 = 50.;
|
||||
pub const TIMESTAMP_FONTSIZE: f32 = 30.;
|
||||
pub const TIMESTAMP_WIDTH: f32 = 135.;
|
||||
pub const MESSAGE_SPACING: f32 = 15.;
|
||||
@@ -143,7 +143,7 @@ mod ui_consts {
|
||||
pub const SENDARROW_NEG_X: f32 = 50.;
|
||||
pub const SENDARROW_NEG_Y: f32 = 32.;
|
||||
pub const SENDBTN_BOX: [f32; 4] = [72., 50., 45., 34.];
|
||||
pub const FONTSIZE: f32 = 20.;
|
||||
pub const FONTSIZE: f32 = 25.;
|
||||
pub const TIMESTAMP_FONTSIZE: f32 = 12.;
|
||||
pub const TIMESTAMP_WIDTH: f32 = 60.;
|
||||
pub const MESSAGE_SPACING: f32 = 5.;
|
||||
@@ -373,7 +373,7 @@ pub async fn make(
|
||||
prop.set_f32(atom, Role::App, 1, CHANNEL_LABEL_Y).unwrap();
|
||||
prop.set_expr(atom, Role::App, 2, expr::load_var("w")).unwrap();
|
||||
prop.set_f32(atom, Role::App, 3, CHATEDIT_HEIGHT).unwrap();
|
||||
node.set_property_f32(atom, Role::App, "font_size", FONTSIZE * 1.2).unwrap();
|
||||
node.set_property_f32(atom, Role::App, "font_size", FONTSIZE).unwrap();
|
||||
node.set_property_str(atom, Role::App, "text", &("#".to_string() + channel)).unwrap();
|
||||
//node.set_property_bool(atom, Role::App, "debug", true).unwrap();
|
||||
//node.set_property_str(atom, Role::App, "text", "anon1").unwrap();
|
||||
@@ -719,7 +719,7 @@ pub async fn make(
|
||||
prop.set_f32(atom, Role::App, 3, 0.).unwrap();
|
||||
|
||||
node.set_property_f32(atom, Role::App, "baseline", TEXTBAR_BASELINE).unwrap();
|
||||
node.set_property_f32(atom, Role::App, "font_size", FONTSIZE * 1.2).unwrap();
|
||||
node.set_property_f32(atom, Role::App, "font_size", FONTSIZE).unwrap();
|
||||
//node.set_property_str(atom, Role::App, "text", "hello king!😁🍆jelly 🍆1234").unwrap();
|
||||
let prop = node.get_property("text_color").unwrap();
|
||||
if COLOR_SCHEME == ColorScheme::PaperLight {
|
||||
@@ -1325,7 +1325,7 @@ pub async fn make(
|
||||
prop.set_f32(atom, Role::App, 1, ACTION_LABEL_POS.y).unwrap();
|
||||
prop.set_f32(atom, Role::App, 2, ACTION_SELECT_ALL_RECT.rhs()).unwrap();
|
||||
prop.set_f32(atom, Role::App, 3, ACTION_SELECT_ALL_RECT.h).unwrap();
|
||||
node.set_property_f32(atom, Role::App, "font_size", FONTSIZE * 1.24).unwrap();
|
||||
node.set_property_f32(atom, Role::App, "font_size", FONTSIZE).unwrap();
|
||||
node.set_property_str(atom, Role::App, "text", "copy paste select all").unwrap();
|
||||
//node.set_property_bool(atom, Role::App, "debug", true).unwrap();
|
||||
//node.set_property_str(atom, Role::App, "text", "anon1").unwrap();
|
||||
|
||||
@@ -54,7 +54,7 @@ mod ui_consts {
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn get_chatdb_path() -> PathBuf {
|
||||
"chatdb"
|
||||
"chatdb".into()
|
||||
}
|
||||
//pub const KING_PATH: &str = "assets/king.png";
|
||||
pub const VID_PATH: &str = "assets/forest_1920x1080.ivf";
|
||||
|
||||
@@ -460,13 +460,7 @@ impl ChatView {
|
||||
return
|
||||
}
|
||||
|
||||
#[cfg(feature = "enable-plugins")]
|
||||
if let Some(url) = get_file_url(&text) {
|
||||
// This is incorrect. Scenegraph paths should not be hardcoded in widgets
|
||||
// nor should there be dependencies on other widgets.
|
||||
// Instead use signals and slots through app layer. See how focus is done with
|
||||
// the edit widgets.
|
||||
let fud = self.sg_root.lookup_node("/plugin/fud").unwrap();
|
||||
msgbuf.insert_filemsg(
|
||||
timest,
|
||||
msg_id,
|
||||
@@ -475,9 +469,17 @@ impl ChatView {
|
||||
url.clone(),
|
||||
);
|
||||
|
||||
let mut data = vec![];
|
||||
url.encode(&mut data).unwrap();
|
||||
fud.call_method("get", data).await.unwrap();
|
||||
// This is incorrect. Scenegraph paths should not be hardcoded in widgets
|
||||
// nor should there be dependencies on other widgets.
|
||||
// Instead use signals and slots through app layer. See how focus is done with
|
||||
// the edit widgets.
|
||||
#[cfg(feature = "enable-plugins")]
|
||||
{
|
||||
let mut data = vec![];
|
||||
url.encode(&mut data).unwrap();
|
||||
let fud = self.sg_root.lookup_node("/plugin/fud").unwrap();
|
||||
fud.call_method("get", data).await.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -606,10 +608,7 @@ impl ChatView {
|
||||
chatmsg.text.clone(),
|
||||
);
|
||||
|
||||
// See comment in handle_insert_line()
|
||||
#[cfg(feature = "enable-plugins")]
|
||||
if let Some(url) = get_file_url(&chatmsg.text) {
|
||||
let fud = self.sg_root.lookup_node("/plugin/fud").unwrap();
|
||||
msgbuf.insert_filemsg(
|
||||
timest,
|
||||
msg_id,
|
||||
@@ -618,9 +617,14 @@ impl ChatView {
|
||||
url.clone(),
|
||||
);
|
||||
|
||||
let mut data = vec![];
|
||||
url.encode(&mut data).unwrap();
|
||||
fud.call_method("get", data).await.unwrap();
|
||||
// See comment in handle_insert_line()
|
||||
#[cfg(feature = "enable-plugins")]
|
||||
{
|
||||
let mut data = vec![];
|
||||
url.encode(&mut data).unwrap();
|
||||
let fud = self.sg_root.lookup_node("/plugin/fud").unwrap();
|
||||
fud.call_method("get", data).await.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
remaining_load_height -= msg_height;
|
||||
|
||||
@@ -35,12 +35,10 @@ use url::Url;
|
||||
|
||||
use super::{max, MessageId, Timestamp};
|
||||
use crate::{
|
||||
gfx::{gfxtag, DrawInstruction, DrawMesh, ManagedTexturePtr, Point, Rectangle, RenderApi},
|
||||
mesh::{
|
||||
Color, MeshBuilder, COLOR_BLUE, COLOR_CYAN, COLOR_GREEN, COLOR_PINK, COLOR_RED, COLOR_WHITE,
|
||||
},
|
||||
gfx::{gfxtag, DrawInstruction, ManagedTexturePtr, Point, Rectangle, RenderApi},
|
||||
mesh::{Color, MeshBuilder, COLOR_CYAN, COLOR_GREEN, COLOR_RED, COLOR_WHITE},
|
||||
prop::{PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr},
|
||||
text::{self, Glyph, GlyphPositionIter, TextShaper, TextShaperPtr},
|
||||
text::{TextShaper, TextShaperPtr},
|
||||
text2,
|
||||
util::enumerate_mut,
|
||||
};
|
||||
@@ -372,12 +370,12 @@ pub struct FileMessage {
|
||||
status: FileMessageStatus,
|
||||
imgbuf: Arc<SyncMutex<Option<GenericImageBuffer>>>,
|
||||
timestamp: Timestamp,
|
||||
glyphs: Vec<Vec<Glyph>>,
|
||||
|
||||
atlas: text::RenderedAtlas,
|
||||
mesh_cache: Option<Vec<DrawInstruction>>,
|
||||
}
|
||||
|
||||
impl FileMessage {
|
||||
// This is not portable across devices and will break
|
||||
const GLOW_SIZE: f32 = 20.;
|
||||
const MARGIN_TOP: f32 = 4.;
|
||||
const MARGIN_BOTTOM: f32 = 10.;
|
||||
@@ -395,20 +393,9 @@ impl FileMessage {
|
||||
timestamp: Timestamp,
|
||||
_nick: String,
|
||||
|
||||
text_shaper: &TextShaper,
|
||||
render_api: &RenderApi,
|
||||
_text_shaper: &TextShaper,
|
||||
_render_api: &RenderApi,
|
||||
) -> Message {
|
||||
let mut glyphs = Vec::new();
|
||||
let mut atlas = text::Atlas::new(render_api, gfxtag!("chatview_filemsg"));
|
||||
|
||||
for str in Self::filestr(&file_url, &status) {
|
||||
let glyphs_ = text_shaper.shape(str, font_size, window_scale);
|
||||
atlas.push(&glyphs_);
|
||||
glyphs.push(glyphs_);
|
||||
}
|
||||
|
||||
let atlas = atlas.make();
|
||||
|
||||
Message::File(Self {
|
||||
font_size,
|
||||
window_scale,
|
||||
@@ -417,8 +404,7 @@ impl FileMessage {
|
||||
status,
|
||||
imgbuf: Arc::new(SyncMutex::new(None)),
|
||||
timestamp,
|
||||
glyphs,
|
||||
atlas,
|
||||
mesh_cache: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -460,31 +446,19 @@ impl FileMessage {
|
||||
&mut self,
|
||||
font_size: f32,
|
||||
window_scale: f32,
|
||||
text_shaper: &TextShaper,
|
||||
render_api: &RenderApi,
|
||||
_text_shaper: &TextShaper,
|
||||
_render_api: &RenderApi,
|
||||
) {
|
||||
self.font_size = font_size;
|
||||
self.window_scale = window_scale;
|
||||
|
||||
self.glyphs = Vec::new();
|
||||
let mut atlas = text::Atlas::new(render_api, gfxtag!("chatview_filemsg"));
|
||||
|
||||
for str in Self::filestr(&self.file_url, &self.status) {
|
||||
let glyphs = text_shaper.shape(str, font_size, window_scale);
|
||||
atlas.push(&glyphs);
|
||||
self.glyphs.push(glyphs);
|
||||
}
|
||||
|
||||
self.atlas = atlas.make();
|
||||
self.mesh_cache = None;
|
||||
}
|
||||
|
||||
fn adjust_width(&mut self, line_width: f32, timestamp_width: f32) {
|
||||
let width = line_width - timestamp_width;
|
||||
// clamp to > 0
|
||||
self.max_width = max(width, 0.);
|
||||
}
|
||||
fn adjust_width(&mut self, line_width: f32, timestamp_width: f32) {}
|
||||
|
||||
fn clear_mesh(&mut self) {}
|
||||
fn clear_mesh(&mut self) {
|
||||
self.mesh_cache = None;
|
||||
}
|
||||
|
||||
fn get_img_size(&self, imgbuf: &ImageBuffer<Rgba<u8>, Vec<u8>>) -> (f32, f32) {
|
||||
let img_w = imgbuf.width() as f32;
|
||||
@@ -497,25 +471,34 @@ impl FileMessage {
|
||||
(img_w * scale, img_h * scale)
|
||||
}
|
||||
|
||||
fn gen_mesh(
|
||||
async fn gen_mesh(
|
||||
&mut self,
|
||||
_clip: &Rectangle,
|
||||
clip: &Rectangle,
|
||||
line_height: f32,
|
||||
msg_spacing: f32,
|
||||
baseline: f32,
|
||||
timestamp_width: f32,
|
||||
_nick_colors: &[Color],
|
||||
timestamp_color: Color,
|
||||
_text_color: Color,
|
||||
_hi_bg_color: Color,
|
||||
_debug_render: bool,
|
||||
render_api: &RenderApi,
|
||||
) -> Vec<DrawMesh> {
|
||||
let uv_rect = Rectangle::from([0., 0., 1., 1.]);
|
||||
) -> Vec<DrawInstruction> {
|
||||
if let Some(instrs) = &self.mesh_cache {
|
||||
return instrs.clone()
|
||||
}
|
||||
|
||||
let imgbuf_ = self.imgbuf.lock();
|
||||
if let Some(ref imgbuf) = *imgbuf_ {
|
||||
let (img_w, img_h) = self.get_img_size(imgbuf);
|
||||
drop(imgbuf_);
|
||||
self.max_width = clip.w - timestamp_width;
|
||||
|
||||
// Extract image size while holding lock, then drop it
|
||||
let mut img_size = None;
|
||||
if let Some(img) = &*self.imgbuf.lock() {
|
||||
img_size = Some(self.get_img_size(img));
|
||||
}
|
||||
|
||||
// Lock is dropped here, safe to await now
|
||||
if let Some((img_w, img_h)) = img_size {
|
||||
let mesh_rect =
|
||||
Rectangle::from([timestamp_width, -img_h - Self::MARGIN_BOTTOM, img_w, img_h]);
|
||||
let texture = self.load_texture(render_api);
|
||||
@@ -524,17 +507,24 @@ impl FileMessage {
|
||||
mesh_gradient.draw_box_shadow(&mesh_rect, glow_color, Self::GLOW_SIZE);
|
||||
|
||||
let mesh_gradient = mesh_gradient.alloc(render_api);
|
||||
let mesh_gradient = mesh_gradient.draw_untextured();
|
||||
let mut instrs = vec![DrawInstruction::Draw(mesh_gradient.draw_untextured())];
|
||||
|
||||
let mut mesh_img = MeshBuilder::new(gfxtag!("file_img"));
|
||||
let uv_rect = Rectangle::from([0., 0., 1., 1.]);
|
||||
mesh_img.draw_box(&mesh_rect, COLOR_WHITE, &uv_rect);
|
||||
let mesh_img = mesh_img.alloc(render_api);
|
||||
let mesh_img = mesh_img.draw_with_textures(vec![texture]);
|
||||
return vec![mesh_img, mesh_gradient];
|
||||
}
|
||||
drop(imgbuf_);
|
||||
instrs.push(DrawInstruction::Draw(mesh_img.draw_with_textures(vec![texture])));
|
||||
|
||||
let mut mesh = MeshBuilder::new(gfxtag!("chatview_filemsg"));
|
||||
self.mesh_cache = Some(instrs.clone());
|
||||
// Image is downloaded so return
|
||||
return instrs;
|
||||
}
|
||||
|
||||
// Image is not downloaded yet
|
||||
|
||||
let mut all_instrs = vec![];
|
||||
|
||||
// Draw background box
|
||||
|
||||
let color = match self.status {
|
||||
FileMessageStatus::Initializing => timestamp_color,
|
||||
@@ -542,43 +532,55 @@ impl FileMessage {
|
||||
FileMessageStatus::Downloaded { .. } => COLOR_GREEN,
|
||||
FileMessageStatus::Error { .. } => COLOR_RED,
|
||||
};
|
||||
let box_height = 2. * line_height + Self::BOX_PADDING_TOP + Self::BOX_PADDING_BOTTOM;
|
||||
|
||||
let mut text_width = 0.;
|
||||
for (i, glyphs) in self.glyphs.iter().enumerate() {
|
||||
let glyph_pos_iter =
|
||||
GlyphPositionIter::new(self.font_size, self.window_scale, &glyphs, baseline);
|
||||
for (mut glyph_rect, glyph) in glyph_pos_iter.zip(glyphs.iter()) {
|
||||
let uv_rect = self.atlas.fetch_uv(glyph.glyph_id).expect("missing glyph UV rect");
|
||||
if glyph_rect.x + glyph_rect.w > text_width {
|
||||
text_width = glyph_rect.x + glyph_rect.w;
|
||||
}
|
||||
glyph_rect.x += timestamp_width + Self::BOX_PADDING_X;
|
||||
glyph_rect.y -= line_height * (self.glyphs.len() - i) as f32 +
|
||||
Self::BOX_PADDING_BOTTOM +
|
||||
Self::MARGIN_BOTTOM;
|
||||
mesh.draw_box(&glyph_rect, color, uv_rect);
|
||||
}
|
||||
}
|
||||
|
||||
let box_width = text_width + Self::BOX_PADDING_X * 2.;
|
||||
let box_height = self.glyphs.len() as f32 * line_height +
|
||||
Self::BOX_PADDING_TOP +
|
||||
Self::BOX_PADDING_BOTTOM;
|
||||
let mesh_rect = Rectangle::from([
|
||||
let mut mesh = MeshBuilder::new(gfxtag!("chatview_filemsg_box"));
|
||||
let box_width = self.max_width + Self::BOX_PADDING_X * 2.;
|
||||
let mesh_rect = Rectangle::new(
|
||||
timestamp_width,
|
||||
-box_height - Self::MARGIN_BOTTOM,
|
||||
-box_height + Self::MARGIN_BOTTOM,
|
||||
box_width,
|
||||
box_height,
|
||||
]);
|
||||
);
|
||||
mesh.draw_outline(&mesh_rect, color, 1.);
|
||||
|
||||
let glow_color = [color[0], color[1], color[2], 0.3];
|
||||
mesh.draw_box_shadow(&mesh_rect, glow_color, Self::GLOW_SIZE);
|
||||
|
||||
let mesh = mesh.alloc(render_api);
|
||||
let mesh = mesh.draw_with_textures(vec![self.atlas.texture.clone()]);
|
||||
|
||||
vec![mesh]
|
||||
all_instrs.push(DrawInstruction::Draw(mesh.draw_untextured()));
|
||||
|
||||
let file_strs = Self::filestr(&self.file_url, &self.status);
|
||||
|
||||
let mut layouts = Vec::with_capacity(file_strs.len());
|
||||
let mut txt_ctx = text2::TEXT_CTX.get().await;
|
||||
for (i, file_str) in file_strs.iter().enumerate() {
|
||||
let layout = txt_ctx.make_layout(
|
||||
file_str,
|
||||
color,
|
||||
self.font_size,
|
||||
line_height / self.font_size,
|
||||
self.window_scale,
|
||||
Some(self.max_width),
|
||||
&[],
|
||||
);
|
||||
layouts.push(layout);
|
||||
}
|
||||
drop(txt_ctx);
|
||||
|
||||
all_instrs
|
||||
.push(DrawInstruction::Move(Point::new(timestamp_width + Self::BOX_PADDING_X, 0.)));
|
||||
let mut text_y_offset = 0.;
|
||||
for (i, (file_str, layout)) in file_strs.iter().zip(layouts.into_iter()).enumerate() {
|
||||
all_instrs.push(DrawInstruction::Move(Point::new(0., -line_height)));
|
||||
|
||||
let instrs =
|
||||
text2::render_layout(&layout, render_api, gfxtag!("chatview_filemsg_text"));
|
||||
all_instrs.extend(instrs);
|
||||
}
|
||||
|
||||
self.mesh_cache = Some(all_instrs.clone());
|
||||
all_instrs
|
||||
}
|
||||
|
||||
fn load_img(&self) -> Option<ImageBuffer<Rgba<u8>, Vec<u8>>> {
|
||||
@@ -625,16 +627,20 @@ impl FileMessage {
|
||||
|
||||
pub fn height(&self, line_height: f32) -> f32 {
|
||||
let imgbuf = self.imgbuf.lock();
|
||||
imgbuf
|
||||
.as_ref()
|
||||
.map(|buf| self.get_img_size(buf).1 as f32 + Self::MARGIN_TOP + Self::MARGIN_BOTTOM)
|
||||
.unwrap_or(
|
||||
line_height * self.glyphs.len() as f32 +
|
||||
Self::BOX_PADDING_TOP +
|
||||
Self::BOX_PADDING_BOTTOM +
|
||||
Self::MARGIN_TOP +
|
||||
Self::MARGIN_BOTTOM,
|
||||
)
|
||||
// If image is downloaded, return image height plus margins
|
||||
if let Some(buf) = &*imgbuf {
|
||||
let img_height = self.get_img_size(buf).1;
|
||||
return img_height + Self::MARGIN_TOP + Self::MARGIN_BOTTOM;
|
||||
}
|
||||
drop(imgbuf);
|
||||
|
||||
// No image yet, so calculate height for text box
|
||||
// filestr() always returns 2 lines: [file_hash, status_string]
|
||||
let text_height = 2. * line_height;
|
||||
let box_padding = Self::BOX_PADDING_TOP + Self::BOX_PADDING_BOTTOM;
|
||||
let margins = Self::MARGIN_TOP + Self::MARGIN_BOTTOM;
|
||||
|
||||
text_height //+ box_padding + margins
|
||||
}
|
||||
|
||||
fn select(&mut self) {}
|
||||
@@ -757,18 +763,20 @@ impl Message {
|
||||
.await
|
||||
}
|
||||
Self::File(m) => {
|
||||
let meshes = m.gen_mesh(
|
||||
m.gen_mesh(
|
||||
clip,
|
||||
line_height,
|
||||
msg_spacing,
|
||||
baseline,
|
||||
timestamp_width,
|
||||
nick_colors,
|
||||
timestamp_color,
|
||||
text_color,
|
||||
hi_bg_color,
|
||||
debug_render,
|
||||
render_api,
|
||||
);
|
||||
meshes.into_iter().map(DrawInstruction::Draw).collect()
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1279,7 +1287,6 @@ impl MessageBuffer {
|
||||
}
|
||||
|
||||
msg.select();
|
||||
|
||||
msg.clear_mesh();
|
||||
break
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user