Compare commits
2 Commits
6344e0ff6a
...
d3565c9ff9
| Author | SHA1 | Date | |
|---|---|---|---|
| d3565c9ff9 | |||
|
|
90776448ce |
@@ -87,6 +87,7 @@ impl<T: TdClientTrait> NavigationMethods<T> for App<T> {
|
||||
#[cfg(feature = "images")]
|
||||
{
|
||||
self.photo_download_rx = None;
|
||||
self.pending_image_open = None;
|
||||
}
|
||||
// Сбрасываем состояние чата в нормальный режим
|
||||
self.chat_state = ChatState::Normal;
|
||||
|
||||
@@ -20,6 +20,19 @@ use crate::types::ChatId;
|
||||
use ratatui::widgets::ListState;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Pending intent to open the image modal once a photo finishes downloading.
|
||||
///
|
||||
/// Set when the user presses `v` on a photo that is still downloading.
|
||||
/// The main loop opens the modal automatically when the download completes.
|
||||
#[cfg(feature = "images")]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PendingImageOpen {
|
||||
pub file_id: i32,
|
||||
pub message_id: crate::types::MessageId,
|
||||
pub photo_width: i32,
|
||||
pub photo_height: i32,
|
||||
}
|
||||
|
||||
/// State of the account switcher modal overlay.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum AccountSwitcherState {
|
||||
@@ -123,6 +136,9 @@ pub struct App<T: TdClientTrait = TdClient> {
|
||||
/// Время последнего рендеринга изображений (для throttling до 15 FPS)
|
||||
#[cfg(feature = "images")]
|
||||
pub last_image_render_time: Option<std::time::Instant>,
|
||||
/// Pending intent: открыть модалку для этого фото когда загрузится
|
||||
#[cfg(feature = "images")]
|
||||
pub pending_image_open: Option<PendingImageOpen>,
|
||||
// Account lock
|
||||
/// Advisory file lock to prevent concurrent access to the same account
|
||||
pub account_lock: Option<std::fs::File>,
|
||||
@@ -219,6 +235,8 @@ impl<T: TdClientTrait> App<T> {
|
||||
image_modal: None,
|
||||
#[cfg(feature = "images")]
|
||||
last_image_render_time: None,
|
||||
#[cfg(feature = "images")]
|
||||
pending_image_open: None,
|
||||
// Voice playback
|
||||
audio_player: crate::audio::AudioPlayer::new().ok(),
|
||||
voice_cache: crate::audio::VoiceCache::new(audio_cache_size_mb).ok(),
|
||||
|
||||
@@ -584,45 +584,44 @@ async fn handle_view_image<T: TdClientTrait>(app: &mut App<T>) {
|
||||
});
|
||||
app.needs_redraw = true;
|
||||
}
|
||||
PhotoDownloadState::Downloading => {
|
||||
app.status_message = Some("Загрузка фото...".to_string());
|
||||
}
|
||||
PhotoDownloadState::NotDownloaded => {
|
||||
// Скачиваем фото и открываем
|
||||
app.status_message = Some("Загрузка фото...".to_string());
|
||||
app.needs_redraw = true;
|
||||
match app.td_client.download_file(file_id).await {
|
||||
Ok(path) => {
|
||||
// Обновляем состояние загрузки в сообщении
|
||||
for msg in app.td_client.current_chat_messages_mut() {
|
||||
if let Some(photo) = msg.photo_info_mut() {
|
||||
if photo.file_id == file_id {
|
||||
photo.download_state = PhotoDownloadState::Downloaded(path.clone());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Открываем модалку
|
||||
app.image_modal = Some(ImageModalState {
|
||||
PhotoDownloadState::NotDownloaded | PhotoDownloadState::Downloading => {
|
||||
// Запоминаем намерение открыть модалку — откроется когда загрузится
|
||||
app.pending_image_open = Some(crate::app::PendingImageOpen {
|
||||
file_id,
|
||||
message_id: msg_id,
|
||||
photo_path: path,
|
||||
photo_width,
|
||||
photo_height,
|
||||
});
|
||||
app.status_message = None;
|
||||
app.status_message = Some("Загрузка фото...".to_string());
|
||||
app.needs_redraw = true;
|
||||
|
||||
// Если нет активной фоновой загрузки — запускаем свою
|
||||
if app.photo_download_rx.is_none() {
|
||||
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
app.photo_download_rx = Some(rx);
|
||||
let client_id = app.td_client.client_id();
|
||||
tokio::spawn(async move {
|
||||
let result = tokio::time::timeout(Duration::from_secs(30), async {
|
||||
match tdlib_rs::functions::download_file(
|
||||
file_id, 1, 0, 0, true, client_id,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(tdlib_rs::enums::File::File(f))
|
||||
if f.local.is_downloading_completed
|
||||
&& !f.local.path.is_empty() =>
|
||||
{
|
||||
Ok(f.local.path)
|
||||
}
|
||||
Err(e) => {
|
||||
for msg in app.td_client.current_chat_messages_mut() {
|
||||
if let Some(photo) = msg.photo_info_mut() {
|
||||
if photo.file_id == file_id {
|
||||
photo.download_state = PhotoDownloadState::Error(e.clone());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
app.error_message = Some(format!("Ошибка загрузки фото: {}", e));
|
||||
app.status_message = None;
|
||||
Ok(_) => Err("Файл не скачан".to_string()),
|
||||
Err(e) => Err(format!("{:?}", e)),
|
||||
}
|
||||
})
|
||||
.await;
|
||||
let result =
|
||||
result.unwrap_or_else(|_| Err("Таймаут загрузки".to_string()));
|
||||
let _ = tx.send((file_id, result));
|
||||
});
|
||||
}
|
||||
}
|
||||
PhotoDownloadState::Error(_) => {
|
||||
|
||||
41
src/main.rs
41
src/main.rs
@@ -216,6 +216,47 @@ async fn run_app<B: ratatui::backend::Backend, T: tdlib::TdClientTrait>(
|
||||
}
|
||||
}
|
||||
}
|
||||
// Если это фото ждёт открытия в модалке — открываем
|
||||
let pending_matches = app
|
||||
.pending_image_open
|
||||
.as_ref()
|
||||
.map(|p| p.file_id == file_id)
|
||||
.unwrap_or(false);
|
||||
if pending_matches {
|
||||
// Ищем путь из обновлённого состояния
|
||||
let downloaded_path = app
|
||||
.td_client
|
||||
.current_chat_messages()
|
||||
.iter()
|
||||
.find_map(|m| {
|
||||
m.photo_info().and_then(|p| {
|
||||
if p.file_id == file_id {
|
||||
if let PhotoDownloadState::Downloaded(ref path) =
|
||||
p.download_state
|
||||
{
|
||||
Some(path.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
});
|
||||
if let (Some(path), Some(pending)) =
|
||||
(downloaded_path, app.pending_image_open.take())
|
||||
{
|
||||
use crate::tdlib::ImageModalState;
|
||||
app.image_modal = Some(ImageModalState {
|
||||
message_id: pending.message_id,
|
||||
photo_path: path,
|
||||
photo_width: pending.photo_width,
|
||||
photo_height: pending.photo_height,
|
||||
});
|
||||
app.status_message = None;
|
||||
got_photos = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if got_photos {
|
||||
|
||||
Reference in New Issue
Block a user