Tauri: Small style compatibility fixes (#6270)

This commit is contained in:
zubiden 2025-09-30 16:52:21 +02:00 committed by Alexander Zinchuk
parent 6e3bbb7f12
commit ad5bba3e6e
13 changed files with 220 additions and 84 deletions

View File

@ -1245,8 +1245,8 @@
"AtDateAgo" = "on {date}";
"AudioPause" = "Pause audio";
"AudioPlay" = "Play audio";
"ToggleUserNotifications" = "Toggle user notifications";
"ToggleChatNotifications" = "Toggle chat notifications";
"AriaToggleUserNotifications" = "Toggle user notifications";
"AriaToggleChatNotifications" = "Toggle chat notifications";
"ChannelInaccessible" = "channel is inaccessible";
"GroupInaccessible" = "group is inaccessible";
"AriaPasswordToggle" = "Toggle password visibility";
@ -2280,4 +2280,4 @@
"ContextMenuHintTouch" = "To edit or reply, close this menu. Then long tap on a message.";
"GiftValueForSaleOnFragment" = "for sale on Fragment";
"GiftValueForSaleOnTelegram" = "for sale on Telegram";
"EmbeddedMessageNoCaption" = "Caption removed";
"EmbeddedMessageNoCaption" = "Caption removed";

View File

@ -423,11 +423,11 @@ const ChatExtra: FC<OwnProps & StateProps> = ({
</ListItem>
)}
{!isInSettings && (
<ListItem icon={isMuted ? 'unmute' : 'mute'} narrow ripple onClick={handleToggleNotifications}>
<span>{oldLang('Notifications')}</span>
<ListItem icon={isMuted ? 'mute' : 'unmute'} narrow ripple onClick={handleToggleNotifications}>
<span>{lang('Notifications')}</span>
<Switcher
id="group-notifications"
label={userId ? 'Toggle User Notifications' : 'Toggle Chat Notifications'}
label={lang(userId ? 'AriaToggleUserNotifications' : 'AriaToggleChatNotifications')}
checked={!isMuted}
inactive
/>

View File

@ -47,7 +47,7 @@
body.is-tauri.is-macos #Main:not(.is-fullscreen) &:not(#TopicListHeader) {
justify-content: space-between;
padding: 0.5rem 0.5rem 0.5rem 4.5rem;
padding: 0.5rem 0.5rem 0.5rem var(--window-controls-width);
.SearchInput {
max-width: calc(100% - 2.75rem);

View File

@ -174,8 +174,8 @@ addCallback((global: GlobalState) => {
if (IS_TAURI) {
document.body.classList.add('is-tauri');
}
if (IS_ELECTRON) { // Legacy
document.body.classList.add('is-electron');
if (IS_ELECTRON) { // Legacy, pretend to be Tauri
document.body.classList.add('is-tauri');
}
});

View File

@ -92,7 +92,7 @@ body.is-ios {
--border-radius-messages-small: 0.5rem;
}
body.is-tauri, body.is-electron {
body.is-tauri {
--custom-cursor: default;
--window-controls-width: 5rem;
}

View File

@ -1051,8 +1051,8 @@ export interface LangPair {
'JustNowAgo': undefined;
'AudioPause': undefined;
'AudioPlay': undefined;
'ToggleUserNotifications': undefined;
'ToggleChatNotifications': undefined;
'AriaToggleUserNotifications': undefined;
'AriaToggleChatNotifications': undefined;
'ChannelInaccessible': undefined;
'GroupInaccessible': undefined;
'AriaPasswordToggle': undefined;

52
tauri/Cargo.lock generated
View File

@ -1605,6 +1605,16 @@ dependencies = [
"version_check",
]
[[package]]
name = "gethostname"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55"
dependencies = [
"rustix",
"windows-targets 0.52.6",
]
[[package]]
name = "getrandom"
version = "0.1.16"
@ -3221,6 +3231,18 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "os_info"
version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0e1ac5fde8d43c34139135df8ea9ee9465394b2d8d20f032d38998f64afffc3"
dependencies = [
"log",
"plist",
"serde",
"windows-sys 0.52.0",
]
[[package]]
name = "os_pipe"
version = "1.2.2"
@ -4838,6 +4860,15 @@ dependencies = [
"syn 2.0.106",
]
[[package]]
name = "sys-locale"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
dependencies = [
"libc",
]
[[package]]
name = "system-deps"
version = "6.2.2"
@ -5142,6 +5173,24 @@ dependencies = [
"url",
]
[[package]]
name = "tauri-plugin-os"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a1c77ebf6f20417ab2a74e8c310820ba52151406d0c80fbcea7df232e3f6ba"
dependencies = [
"gethostname",
"log",
"os_info",
"serde",
"serde_json",
"serialize-to-javascript",
"sys-locale",
"tauri",
"tauri-plugin",
"thiserror 2.0.16",
]
[[package]]
name = "tauri-plugin-process"
version = "2.3.0"
@ -5351,7 +5400,7 @@ dependencies = [
[[package]]
name = "telegram_air"
version = "2.8.8"
version = "2.8.9"
dependencies = [
"ab_glyph",
"cocoa",
@ -5368,6 +5417,7 @@ dependencies = [
"tauri-plugin-fs",
"tauri-plugin-log",
"tauri-plugin-notification",
"tauri-plugin-os",
"tauri-plugin-process",
"tauri-plugin-shell",
"tauri-plugin-single-instance",

View File

@ -1,6 +1,6 @@
[package]
name = "telegram_air"
version = "2.8.8"
version = "2.8.9"
description = "Telegram Air"
authors = ["Alexander Zinchuk"]
license = "GPLv3"
@ -31,6 +31,7 @@ url = "2.5.7"
image = "0.25.6"
imageproc = "0.25.0"
ab_glyph = "0.2.31"
tauri-plugin-os = "2"
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\"))".dependencies]
tauri-plugin-single-instance = { version = "2.3.3", features = ["deep-link"] }

View File

@ -1,3 +1,3 @@
fn main() {
tauri_build::build()
tauri_build::build()
}

View File

@ -5,46 +5,46 @@ use tauri_plugin_deep_link::DeepLinkExt;
pub struct Deeplink;
impl Deeplink {
pub fn init() -> Self {
Self {}
}
pub fn init() -> Self {
Self {}
}
pub fn setup(&self, app: &tauri::AppHandle) -> Result<(), Box<dyn std::error::Error>> {
// Clone the app handle for use in the closure
let app_handle = app.clone();
pub fn setup(&self, app: &tauri::AppHandle) -> Result<(), Box<dyn std::error::Error>> {
// Clone the app handle for use in the closure
let app_handle = app.clone();
// Set up the deep link event handler
app.deep_link().on_open_url(move |event| {
// Store URLs to avoid calling event.urls() multiple times (it consumes the event)
let urls = event.urls();
info!("Deep link received: {:?}", urls);
// Set up the deep link event handler
app.deep_link().on_open_url(move |event| {
// Store URLs to avoid calling event.urls() multiple times (it consumes the event)
let urls = event.urls();
info!("Deep link received: {:?}", urls);
// Get the main window
if let Some(window) = app_handle.get_webview_window("main") {
// Emit the deep link event to the frontend
if let Err(err) = window.emit("deeplink", &urls) {
info!("Error emitting deeplink event: {:?}", err);
}
// Get the main window
if let Some(window) = app_handle.get_webview_window("main") {
// Emit the deep link event to the frontend
if let Err(err) = window.emit("deeplink", &urls) {
info!("Error emitting deeplink event: {:?}", err);
}
// Request user attention and focus the window
if let Err(err) = window.request_user_attention(Some(UserAttentionType::Informational)) {
info!("Error requesting user attention: {:?}", err);
}
// Request user attention and focus the window
if let Err(err) = window.request_user_attention(Some(UserAttentionType::Informational)) {
info!("Error requesting user attention: {:?}", err);
}
if let Err(err) = window.show() {
info!("Error showing window: {:?}", err);
}
if let Err(err) = window.show() {
info!("Error showing window: {:?}", err);
}
if let Err(err) = window.unminimize() {
info!("Error unminimizing window: {:?}", err);
}
if let Err(err) = window.unminimize() {
info!("Error unminimizing window: {:?}", err);
}
if let Err(err) = window.set_focus() {
info!("Error setting focus: {:?}", err);
}
}
});
if let Err(err) = window.set_focus() {
info!("Error setting focus: {:?}", err);
}
}
});
Ok(())
}
Ok(())
}
}

View File

@ -33,9 +33,19 @@ impl Default for AppStateStruct {
pub type AppState = Mutex<AppStateStruct>;
pub const TRAFFIC_LIGHT_POSITION_OVERLAY: LogicalPosition<f64> = LogicalPosition::new(12.0, 26.0);
pub const TRAFFIC_LIGHT_POSITION_OVERLAY_LEGACY: LogicalPosition<f64> = LogicalPosition::new(12.0, 26.0);
pub const TRAFFIC_LIGHT_POSITION_OVERLAY_26: LogicalPosition<f64> = LogicalPosition::new(12.0, 30.0);
pub const TRAFFIC_LIGHT_POSITION_DEFAULT: LogicalPosition<f64> = LogicalPosition::new(12.0, 12.0);
pub static TRAFFIC_LIGHT_POSITION_OVERLAY: LazyLock<LogicalPosition<f64>> = LazyLock::new(|| {
if let tauri_plugin_os::Version::Semantic(major, _, _) = tauri_plugin_os::version() {
if major >= 26 {
return TRAFFIC_LIGHT_POSITION_OVERLAY_26;
}
}
TRAFFIC_LIGHT_POSITION_OVERLAY_LEGACY
});
pub const WINDOW_WIDTH: f64 = 1088.0;
pub const WINDOW_HEIGHT: f64 = 700.0;
pub const WINDOW_MIN_WIDTH: f64 = 360.0;
@ -90,6 +100,7 @@ pub fn run() {
open_new_window(app.clone(), BASE_URL.to_string()).unwrap();
}
}))
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_notification::init())
@ -124,7 +135,7 @@ pub fn run() {
state.title.clone()
};
let traffic_position = if state.is_overlay {
TRAFFIC_LIGHT_POSITION_OVERLAY
*TRAFFIC_LIGHT_POSITION_OVERLAY
} else {
TRAFFIC_LIGHT_POSITION_DEFAULT
};
@ -199,7 +210,7 @@ fn mark_title_bar_overlay(window: tauri::WebviewWindow, is_overlay: bool) {
mac::update_window_title(
base_window.clone(),
"".to_string(),
TRAFFIC_LIGHT_POSITION_OVERLAY,
*TRAFFIC_LIGHT_POSITION_OVERLAY,
);
}
} else {
@ -297,7 +308,10 @@ pub(crate) fn open_new_window(
.inner_size(WINDOW_WIDTH, WINDOW_HEIGHT)
.min_inner_size(WINDOW_MIN_WIDTH, WINDOW_MIN_HEIGHT)
.disable_drag_drop_handler() // Required for Drag & Drop on Windows
.initialization_script(&format!("window.tauri = {{ version: '{}' }};", env!("CARGO_PKG_VERSION")))
.initialization_script(&format!(
"window.tauri = {{ version: '{}' }};",
env!("CARGO_PKG_VERSION")
))
.on_download(|window, event| {
match event {
#[allow(unused_variables)]
@ -345,7 +359,7 @@ pub(crate) fn open_new_window(
#[cfg(target_os = "macos")]
if let Some(base_window) = app.get_window(&window_label) {
mac::setup_traffic_light_positioner(&base_window, TRAFFIC_LIGHT_POSITION_OVERLAY);
mac::setup_traffic_light_positioner(&base_window, *TRAFFIC_LIGHT_POSITION_OVERLAY);
}
// Apply stored notification count to the new window

View File

@ -2,5 +2,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
app_lib::run();
app_lib::run();
}

View File

@ -1,8 +1,8 @@
use image::{Rgba, RgbaImage, imageops};
use imageproc::drawing::{draw_filled_rect_mut, draw_filled_circle_mut, draw_text_mut, text_size};
use imageproc::rect::Rect;
use imageproc::filter::gaussian_blur_f32;
use ab_glyph::{FontRef, PxScale};
use image::{Rgba, RgbaImage, imageops};
use imageproc::drawing::{draw_filled_circle_mut, draw_filled_rect_mut, draw_text_mut, text_size};
use imageproc::filter::gaussian_blur_f32;
use imageproc::rect::Rect;
use std::io::Cursor;
use tauri::image::Image;
@ -47,21 +47,25 @@ pub fn set_badge_count_icon(window: &tauri::WebviewWindow, amount: i32, is_muted
}
pub fn generate_counter_png(size: u32, count: i32, is_muted: bool) -> Vec<u8> {
let background_color = if is_muted { BADGE_BACKGROUND_COLOR_MUTED } else { BADGE_BACKGROUND_COLOR };
let background_color = if is_muted {
BADGE_BACKGROUND_COLOR_MUTED
} else {
BADGE_BACKGROUND_COLOR
};
// Prepare text properties
let (text, font, scale, text_width, text_height) = if count >= 0 {
let text = if count < 100 {
count.to_string()
count.to_string()
} else {
format!("..{:02}", count % 100)
format!("..{:02}", count % 100)
};
let font = FontRef::try_from_slice(FONT).expect("Invalid font");
let scale = {
let base = if text.len() < 3 { 0.9 } else { 0.75 };
let calculated_scale = (base * size as f32).ceil();
PxScale::from(calculated_scale)
let base = if text.len() < 3 { 0.9 } else { 0.75 };
let calculated_scale = (base * size as f32).ceil();
PxScale::from(calculated_scale)
};
let (text_width, text_height) = text_size(scale, &font, &text);
@ -102,7 +106,15 @@ pub fn generate_counter_png(size: u32, count: i32, is_muted: bool) -> Vec<u8> {
badge_height / 2
};
draw_rounded_rect(&mut img, edge_space, edge_space, badge_width, badge_height, corner_radius, background_color);
draw_rounded_rect(
&mut img,
edge_space,
edge_space,
badge_width,
badge_height,
corner_radius,
background_color,
);
// Apply gaussian blur for antialiasing effect
img = gaussian_blur_f32(&img, 0.75);
@ -111,15 +123,25 @@ pub fn generate_counter_png(size: u32, count: i32, is_muted: bool) -> Vec<u8> {
let x = edge_space as f32 + ((badge_width as f32 - text_width as f32) / 2.0).ceil();
let baseline_offset = scale.y * 0.15;
let y = edge_space as f32 + ((badge_height as f32 - text_height as f32) / 2.0 - baseline_offset).ceil();
let y = edge_space as f32
+ ((badge_height as f32 - text_height as f32) / 2.0 - baseline_offset).ceil();
draw_text_mut(&mut img, BADGE_TEXT_COLOR, x as i32, y as i32, scale, &font, &text);
draw_text_mut(
&mut img,
BADGE_TEXT_COLOR,
x as i32,
y as i32,
scale,
&font,
&text,
);
}
let mut buffer = Vec::new();
let mut cursor = Cursor::new(&mut buffer);
img.write_to(&mut cursor, image::ImageFormat::Png)
.expect("PNG encode failed");
img
.write_to(&mut cursor, image::ImageFormat::Png)
.expect("PNG encode failed");
buffer
}
@ -130,8 +152,9 @@ pub fn overlay_tray_icon(icon: &Image, counter: &Image) -> Image<'static> {
let icon_img = image::RgbaImage::from_raw(icon.width(), icon.height(), icon_rgba.to_vec())
.expect("Failed to create RgbaImage from icon data");
let counter_img = image::RgbaImage::from_raw(counter.width(), counter.height(), counter_rgba.to_vec())
.expect("Failed to create RgbaImage from counter data");
let counter_img =
image::RgbaImage::from_raw(counter.width(), counter.height(), counter_rgba.to_vec())
.expect("Failed to create RgbaImage from counter data");
let mut result = icon_img.clone();
@ -150,7 +173,8 @@ pub fn overlay_tray_icon(icon: &Image, counter: &Image) -> Image<'static> {
// Convert back to tauri Image
let mut buffer = Vec::new();
let mut cursor = Cursor::new(&mut buffer);
result.write_to(&mut cursor, image::ImageFormat::Png)
result
.write_to(&mut cursor, image::ImageFormat::Png)
.expect("PNG encode failed");
Image::from_bytes(&buffer).expect("Failed to create Image from bytes")
@ -163,33 +187,80 @@ fn draw_rounded_rect(
width: u32,
height: u32,
radius: u32,
color: Rgba<u8>
color: Rgba<u8>,
) {
let radius = radius.min(width / 2).min(height / 2);
if radius == 0 {
draw_filled_rect_mut(img, Rect::at(x as i32, y as i32).of_size(width, height), color);
draw_filled_rect_mut(
img,
Rect::at(x as i32, y as i32).of_size(width, height),
color,
);
return;
}
if width > 2 * radius && height > 2 * radius {
draw_filled_rect_mut(img, Rect::at((x + radius) as i32, (y + radius) as i32).of_size(width - 2 * radius, height - 2 * radius), color);
draw_filled_rect_mut(
img,
Rect::at((x + radius) as i32, (y + radius) as i32)
.of_size(width - 2 * radius, height - 2 * radius),
color,
);
}
if width > 2 * radius {
draw_filled_rect_mut(img, Rect::at((x + radius) as i32, y as i32).of_size(width - 2 * radius, radius), color);
draw_filled_rect_mut(img, Rect::at((x + radius) as i32, (y + height - radius) as i32).of_size(width - 2 * radius, radius), color);
draw_filled_rect_mut(
img,
Rect::at((x + radius) as i32, y as i32).of_size(width - 2 * radius, radius),
color,
);
draw_filled_rect_mut(
img,
Rect::at((x + radius) as i32, (y + height - radius) as i32)
.of_size(width - 2 * radius, radius),
color,
);
}
if height > 2 * radius {
draw_filled_rect_mut(img, Rect::at(x as i32, (y + radius) as i32).of_size(radius, height - 2 * radius), color);
draw_filled_rect_mut(img, Rect::at((x + width - radius) as i32, (y + radius) as i32).of_size(radius, height - 2 * radius), color);
draw_filled_rect_mut(
img,
Rect::at(x as i32, (y + radius) as i32).of_size(radius, height - 2 * radius),
color,
);
draw_filled_rect_mut(
img,
Rect::at((x + width - radius) as i32, (y + radius) as i32)
.of_size(radius, height - 2 * radius),
color,
);
}
let radius_i32 = radius as i32;
draw_filled_circle_mut(img, ((x + radius) as i32, (y + radius) as i32), radius_i32, color);
draw_filled_circle_mut(img, ((x + width - radius) as i32, (y + radius) as i32), radius_i32, color);
draw_filled_circle_mut(img, ((x + radius) as i32, (y + height - radius) as i32), radius_i32, color);
draw_filled_circle_mut(img, ((x + width - radius) as i32, (y + height - radius) as i32), radius_i32, color);
draw_filled_circle_mut(
img,
((x + radius) as i32, (y + radius) as i32),
radius_i32,
color,
);
draw_filled_circle_mut(
img,
((x + width - radius) as i32, (y + radius) as i32),
radius_i32,
color,
);
draw_filled_circle_mut(
img,
((x + radius) as i32, (y + height - radius) as i32),
radius_i32,
color,
);
draw_filled_circle_mut(
img,
((x + width - radius) as i32, (y + height - radius) as i32),
radius_i32,
color,
);
}