mirror of
https://github.com/chatmail/core.git
synced 2026-05-20 07:16:31 +03:00
api!: Contact::get_color(): Preserve address-based color hue for SELF
4010c60e7b "feat: use key fingerprints for color generation" changes
colors for contacts including SELF. Even if an avatar is set, the self-color is visible in
e.g. replies to outgoing messages.
This adds `Config::Selfcolor` and sets it in a migration. This doesn't preserve the old
address-based color accurately because the old code generating colors is already dropped, so this
only preserves the color angle (hue).
This commit is contained in:
@@ -4311,7 +4311,8 @@ pub unsafe extern "C" fn dc_contact_get_color(contact: *mut dc_contact_t) -> u32
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
let ffi_contact = &*contact;
|
let ffi_contact = &*contact;
|
||||||
ffi_contact.contact.get_color()
|
let ctx = &*ffi_contact.context;
|
||||||
|
block_on(ffi_contact.contact.get_color(ctx)).unwrap_or_log_default(ctx, "Failed get_color")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|||||||
@@ -32,7 +32,10 @@ impl Account {
|
|||||||
let addr = ctx.get_config(Config::Addr).await?;
|
let addr = ctx.get_config(Config::Addr).await?;
|
||||||
let profile_image = ctx.get_config(Config::Selfavatar).await?;
|
let profile_image = ctx.get_config(Config::Selfavatar).await?;
|
||||||
let color = color_int_to_hex_string(
|
let color = color_int_to_hex_string(
|
||||||
Contact::get_by_id(ctx, ContactId::SELF).await?.get_color(),
|
Contact::get_by_id(ctx, ContactId::SELF)
|
||||||
|
.await?
|
||||||
|
.get_color(ctx)
|
||||||
|
.await?,
|
||||||
);
|
);
|
||||||
let private_tag = ctx.get_config(Config::PrivateTag).await?;
|
let private_tag = ctx.get_config(Config::PrivateTag).await?;
|
||||||
Ok(Account::Configured {
|
Ok(Account::Configured {
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ impl ContactObject {
|
|||||||
|
|
||||||
Ok(ContactObject {
|
Ok(ContactObject {
|
||||||
address: contact.get_addr().to_owned(),
|
address: contact.get_addr().to_owned(),
|
||||||
color: color_int_to_hex_string(contact.get_color()),
|
color: color_int_to_hex_string(contact.get_color(context).await?),
|
||||||
auth_name: contact.get_authname().to_owned(),
|
auth_name: contact.get_authname().to_owned(),
|
||||||
status: contact.get_status().to_owned(),
|
status: contact.get_status().to_owned(),
|
||||||
display_name: contact.get_display_name().to_owned(),
|
display_name: contact.get_display_name().to_owned(),
|
||||||
|
|||||||
@@ -162,7 +162,9 @@ impl MessageObject {
|
|||||||
message_id: quote.get_id().to_u32(),
|
message_id: quote.get_id().to_u32(),
|
||||||
chat_id: quote.get_chat_id().to_u32(),
|
chat_id: quote.get_chat_id().to_u32(),
|
||||||
author_display_name: quote_author.get_display_name().to_owned(),
|
author_display_name: quote_author.get_display_name().to_owned(),
|
||||||
author_display_color: color_int_to_hex_string(quote_author.get_color()),
|
author_display_color: color_int_to_hex_string(
|
||||||
|
quote_author.get_color(context).await?,
|
||||||
|
),
|
||||||
override_sender_name: quote.get_override_sender_name(),
|
override_sender_name: quote.get_override_sender_name(),
|
||||||
image: if quote.get_viewtype() == Viewtype::Image
|
image: if quote.get_viewtype() == Viewtype::Image
|
||||||
|| quote.get_viewtype() == Viewtype::Gif
|
|| quote.get_viewtype() == Viewtype::Gif
|
||||||
@@ -581,7 +583,7 @@ impl MessageSearchResult {
|
|||||||
id: msg_id.to_u32(),
|
id: msg_id.to_u32(),
|
||||||
author_profile_image: profile_image,
|
author_profile_image: profile_image,
|
||||||
author_name,
|
author_name,
|
||||||
author_color: color_int_to_hex_string(sender.get_color()),
|
author_color: color_int_to_hex_string(sender.get_color(context).await?),
|
||||||
author_id: sender.id.to_u32(),
|
author_id: sender.id.to_u32(),
|
||||||
chat_id: chat.id.to_u32(),
|
chat_id: chat.id.to_u32(),
|
||||||
chat_name: chat.get_name().to_owned(),
|
chat_name: chat.get_name().to_owned(),
|
||||||
|
|||||||
@@ -1807,7 +1807,7 @@ impl Chat {
|
|||||||
let contacts = get_chat_contacts(context, self.id).await?;
|
let contacts = get_chat_contacts(context, self.id).await?;
|
||||||
if let Some(contact_id) = contacts.first() {
|
if let Some(contact_id) = contacts.first() {
|
||||||
if let Ok(contact) = Contact::get_by_id(context, *contact_id).await {
|
if let Ok(contact) = Contact::get_by_id(context, *contact_id).await {
|
||||||
color = contact.get_color();
|
color = contact.get_color(context).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if !self.grpid.is_empty() {
|
} else if !self.grpid.is_empty() {
|
||||||
|
|||||||
@@ -136,6 +136,9 @@ pub enum Config {
|
|||||||
/// Own name to use in the `From:` field when sending messages.
|
/// Own name to use in the `From:` field when sending messages.
|
||||||
Displayname,
|
Displayname,
|
||||||
|
|
||||||
|
/// Own color to use in the avatar placeholder and replies to outgoing messages.
|
||||||
|
Selfcolor,
|
||||||
|
|
||||||
/// Own status to display, sent in message footer.
|
/// Own status to display, sent in message footer.
|
||||||
Selfstatus,
|
Selfstatus,
|
||||||
|
|
||||||
@@ -474,6 +477,7 @@ impl Config {
|
|||||||
| Self::MvboxMove
|
| Self::MvboxMove
|
||||||
| Self::ShowEmails
|
| Self::ShowEmails
|
||||||
| Self::Selfavatar
|
| Self::Selfavatar
|
||||||
|
| Self::Selfcolor
|
||||||
| Self::Selfstatus,
|
| Self::Selfstatus,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -833,7 +837,7 @@ impl Context {
|
|||||||
}
|
}
|
||||||
if matches!(
|
if matches!(
|
||||||
key,
|
key,
|
||||||
Config::Displayname | Config::Selfavatar | Config::PrivateTag
|
Config::Displayname | Config::Selfavatar | Config::Selfcolor | Config::PrivateTag
|
||||||
) {
|
) {
|
||||||
self.emit_event(EventType::AccountsItemChanged);
|
self.emit_event(EventType::AccountsItemChanged);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -245,6 +245,7 @@ async fn test_sync() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
test_config_str(&alice0, &alice1, Config::Displayname, "Alice Sync").await?;
|
test_config_str(&alice0, &alice1, Config::Displayname, "Alice Sync").await?;
|
||||||
|
test_config_str(&alice0, &alice1, Config::Selfcolor, "255").await?;
|
||||||
test_config_str(&alice0, &alice1, Config::Selfstatus, "My status").await?;
|
test_config_str(&alice0, &alice1, Config::Selfstatus, "My status").await?;
|
||||||
|
|
||||||
assert!(alice0.get_config(Config::Selfavatar).await?.is_none());
|
assert!(alice0.get_config(Config::Selfavatar).await?.is_none());
|
||||||
|
|||||||
@@ -1579,11 +1579,17 @@ impl Contact {
|
|||||||
/// or email address (for address-contacts) and can be used
|
/// or email address (for address-contacts) and can be used
|
||||||
/// for an fallback avatar with white initials
|
/// for an fallback avatar with white initials
|
||||||
/// as well as for headlines in bubbles of group chats.
|
/// as well as for headlines in bubbles of group chats.
|
||||||
pub fn get_color(&self) -> u32 {
|
pub async fn get_color(&self, context: &Context) -> Result<u32> {
|
||||||
|
if self.id == ContactId::SELF {
|
||||||
|
if let Some(v) = context.get_config_opt_parsed(Config::Selfcolor).await? {
|
||||||
|
return Ok(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(fingerprint) = self.fingerprint() {
|
if let Some(fingerprint) = self.fingerprint() {
|
||||||
str_to_color(&fingerprint.hex())
|
Ok(str_to_color(&fingerprint.hex()))
|
||||||
} else {
|
} else {
|
||||||
str_to_color(&self.addr.to_lowercase())
|
Ok(str_to_color(&self.addr.to_lowercase()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -758,17 +758,26 @@ async fn test_lookup_id_by_addr() {
|
|||||||
async fn test_contact_get_color() -> Result<()> {
|
async fn test_contact_get_color() -> Result<()> {
|
||||||
let t = TestContext::new().await;
|
let t = TestContext::new().await;
|
||||||
let contact_id = Contact::create(&t, "name", "name@example.net").await?;
|
let contact_id = Contact::create(&t, "name", "name@example.net").await?;
|
||||||
let color1 = Contact::get_by_id(&t, contact_id).await?.get_color();
|
let color1 = Contact::get_by_id(&t, contact_id)
|
||||||
|
.await?
|
||||||
|
.get_color(&t)
|
||||||
|
.await?;
|
||||||
assert_eq!(color1, 0x4947dc);
|
assert_eq!(color1, 0x4947dc);
|
||||||
|
|
||||||
let t = TestContext::new().await;
|
let t = TestContext::new().await;
|
||||||
let contact_id = Contact::create(&t, "prename name", "name@example.net").await?;
|
let contact_id = Contact::create(&t, "prename name", "name@example.net").await?;
|
||||||
let color2 = Contact::get_by_id(&t, contact_id).await?.get_color();
|
let color2 = Contact::get_by_id(&t, contact_id)
|
||||||
|
.await?
|
||||||
|
.get_color(&t)
|
||||||
|
.await?;
|
||||||
assert_eq!(color2, color1);
|
assert_eq!(color2, color1);
|
||||||
|
|
||||||
let t = TestContext::new().await;
|
let t = TestContext::new().await;
|
||||||
let contact_id = Contact::create(&t, "Name", "nAme@exAmple.NET").await?;
|
let contact_id = Contact::create(&t, "Name", "nAme@exAmple.NET").await?;
|
||||||
let color3 = Contact::get_by_id(&t, contact_id).await?.get_color();
|
let color3 = Contact::get_by_id(&t, contact_id)
|
||||||
|
.await?
|
||||||
|
.get_color(&t)
|
||||||
|
.await?;
|
||||||
assert_eq!(color3, color1);
|
assert_eq!(color3, color1);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -277,6 +277,7 @@ async fn test_get_info_completeness() {
|
|||||||
"mail_security",
|
"mail_security",
|
||||||
"notify_about_wrong_pw",
|
"notify_about_wrong_pw",
|
||||||
"self_reporting_id",
|
"self_reporting_id",
|
||||||
|
"selfcolor",
|
||||||
"selfstatus",
|
"selfstatus",
|
||||||
"send_server",
|
"send_server",
|
||||||
"send_user",
|
"send_user",
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ async fn self_info(context: &Context) -> Result<(Option<Vec<u8>>, String, String
|
|||||||
None => contact.get_addr().to_string(),
|
None => contact.get_addr().to_string(),
|
||||||
};
|
};
|
||||||
let addr = contact.get_addr().to_string();
|
let addr = contact.get_addr().to_string();
|
||||||
let color = color_int_to_hex_string(contact.get_color());
|
let color = color_int_to_hex_string(contact.get_color(context).await?);
|
||||||
Ok((avatar, displayname, addr, color))
|
Ok((avatar, displayname, addr, color))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1261,6 +1261,30 @@ CREATE INDEX gossip_timestamp_index ON gossip_timestamp (chat_id, fingerprint);
|
|||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inc_and_check(&mut migration_version, 134)?;
|
||||||
|
if dbversion < migration_version {
|
||||||
|
let trans_fn = |t: &mut rusqlite::Transaction| {
|
||||||
|
let Some(addr): Option<String> = t
|
||||||
|
.query_row(
|
||||||
|
"SELECT value FROM config WHERE keyname='configured_addr'",
|
||||||
|
(),
|
||||||
|
|row| row.get(0),
|
||||||
|
)
|
||||||
|
.optional()?
|
||||||
|
else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
let color = crate::color::str_to_color(&addr.to_lowercase());
|
||||||
|
t.execute(
|
||||||
|
"INSERT OR IGNORE INTO config (keyname, value) VALUES ('selfcolor', ?)",
|
||||||
|
(color,),
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
sql.execute_migration_transaction(trans_fn, migration_version)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
let new_version = sql
|
let new_version = sql
|
||||||
.get_raw_config_int(VERSION_CFG)
|
.get_raw_config_int(VERSION_CFG)
|
||||||
.await?
|
.await?
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ pub(crate) async fn intercept_get_updates(
|
|||||||
hash_map::Entry::Vacant(e) => {
|
hash_map::Entry::Vacant(e) => {
|
||||||
let contact = Contact::get_by_id(context, location.contact_id).await?;
|
let contact = Contact::get_by_id(context, location.contact_id).await?;
|
||||||
let name = contact.get_display_name().to_string();
|
let name = contact.get_display_name().to_string();
|
||||||
let color = color_int_to_hex_string(contact.get_color());
|
let color = color_int_to_hex_string(contact.get_color(context).await?);
|
||||||
e.insert((name, color)).clone()
|
e.insert((name, color)).clone()
|
||||||
}
|
}
|
||||||
hash_map::Entry::Occupied(e) => e.get().clone(),
|
hash_map::Entry::Occupied(e) => e.get().clone(),
|
||||||
|
|||||||
Reference in New Issue
Block a user