style: auto-format entire codebase with cargo fmt (stable rustfmt.toml)
Some checks failed
ci/woodpecker/pr/check Pipeline failed
CI / Check (pull_request) Has been cancelled
CI / Format (pull_request) Has been cancelled
CI / Clippy (pull_request) Has been cancelled
CI / Build (macos-latest) (pull_request) Has been cancelled
CI / Build (ubuntu-latest) (pull_request) Has been cancelled
CI / Build (windows-latest) (pull_request) Has been cancelled

This commit is contained in:
Mikhail Kilin
2026-02-22 17:09:51 +03:00
parent 2442a90e23
commit 264f183510
90 changed files with 1632 additions and 1450 deletions

View File

@@ -6,7 +6,6 @@
/// - По статусу (archived, muted, и т.д.)
///
/// Используется как в App, так и в UI слое для консистентной фильтрации.
use crate::tdlib::ChatInfo;
/// Критерии фильтрации чатов
@@ -42,18 +41,12 @@ impl ChatFilterCriteria {
/// Фильтр только по папке
pub fn by_folder(folder_id: Option<i32>) -> Self {
Self {
folder_id,
..Default::default()
}
Self { folder_id, ..Default::default() }
}
/// Фильтр только по поисковому запросу
pub fn by_search(query: String) -> Self {
Self {
search_query: Some(query),
..Default::default()
}
Self { search_query: Some(query), ..Default::default() }
}
/// Builder: установить папку
@@ -176,10 +169,7 @@ impl ChatFilter {
///
/// let filtered = ChatFilter::filter(&all_chats, &criteria);
/// ```
pub fn filter<'a>(
chats: &'a [ChatInfo],
criteria: &ChatFilterCriteria,
) -> Vec<&'a ChatInfo> {
pub fn filter<'a>(chats: &'a [ChatInfo], criteria: &ChatFilterCriteria) -> Vec<&'a ChatInfo> {
chats.iter().filter(|chat| criteria.matches(chat)).collect()
}
@@ -309,8 +299,7 @@ mod tests {
let filtered = ChatFilter::filter(&chats, &criteria);
assert_eq!(filtered.len(), 2); // Chat 1 and Chat 3 have unread
let criteria = ChatFilterCriteria::new()
.pinned_only(true);
let criteria = ChatFilterCriteria::new().pinned_only(true);
let filtered = ChatFilter::filter(&chats, &criteria);
assert_eq!(filtered.len(), 1); // Only Chat 1 is pinned
@@ -330,5 +319,4 @@ mod tests {
assert_eq!(ChatFilter::count_unread(&chats, &criteria), 15); // 5 + 10
assert_eq!(ChatFilter::count_unread_mentions(&chats, &criteria), 3); // 1 + 2
}
}

View File

@@ -2,8 +2,8 @@
//!
//! Handles reply, forward, and draft functionality
use crate::app::{App, ChatState};
use crate::app::methods::messages::MessageMethods;
use crate::app::{App, ChatState};
use crate::tdlib::{MessageInfo, TdClientTrait};
/// Compose methods for reply/forward/draft
@@ -44,9 +44,7 @@ pub trait ComposeMethods<T: TdClientTrait> {
impl<T: TdClientTrait> ComposeMethods<T> for App<T> {
fn start_reply_to_selected(&mut self) -> bool {
if let Some(msg) = self.get_selected_message() {
self.chat_state = ChatState::Reply {
message_id: msg.id(),
};
self.chat_state = ChatState::Reply { message_id: msg.id() };
return true;
}
false
@@ -72,9 +70,7 @@ impl<T: TdClientTrait> ComposeMethods<T> for App<T> {
fn start_forward_selected(&mut self) -> bool {
if let Some(msg) = self.get_selected_message() {
self.chat_state = ChatState::Forward {
message_id: msg.id(),
};
self.chat_state = ChatState::Forward { message_id: msg.id() };
// Сбрасываем выбор чата на первый
self.chat_list_state.select(Some(0));
return true;

View File

@@ -61,8 +61,7 @@ impl<T: TdClientTrait> MessageMethods<T> for App<T> {
// Перескакиваем через все сообщения текущего альбома назад
let mut new_index = *selected_index - 1;
if current_album_id != 0 {
while new_index > 0
&& messages[new_index].media_album_id() == current_album_id
while new_index > 0 && messages[new_index].media_album_id() == current_album_id
{
new_index -= 1;
}
@@ -125,9 +124,9 @@ impl<T: TdClientTrait> MessageMethods<T> for App<T> {
}
fn get_selected_message(&self) -> Option<MessageInfo> {
self.chat_state.selected_message_index().and_then(|idx| {
self.td_client.current_chat_messages().get(idx).cloned()
})
self.chat_state
.selected_message_index()
.and_then(|idx| self.td_client.current_chat_messages().get(idx).cloned())
}
fn start_editing_selected(&mut self) -> bool {
@@ -158,10 +157,7 @@ impl<T: TdClientTrait> MessageMethods<T> for App<T> {
if let Some((id, content, idx)) = msg_data {
self.cursor_position = content.chars().count();
self.message_input = content;
self.chat_state = ChatState::Editing {
message_id: id,
selected_index: idx,
};
self.chat_state = ChatState::Editing { message_id: id, selected_index: idx };
return true;
}
false

View File

@@ -7,14 +7,14 @@
//! - search: Search in chats and messages
//! - modal: Modal dialogs (Profile, Pinned, Reactions, Delete)
pub mod navigation;
pub mod messages;
pub mod compose;
pub mod search;
pub mod messages;
pub mod modal;
pub mod navigation;
pub mod search;
pub use navigation::NavigationMethods;
pub use messages::MessageMethods;
pub use compose::ComposeMethods;
pub use search::SearchMethods;
pub use messages::MessageMethods;
pub use modal::ModalMethods;
pub use navigation::NavigationMethods;
pub use search::SearchMethods;

View File

@@ -106,10 +106,7 @@ impl<T: TdClientTrait> ModalMethods<T> for App<T> {
fn enter_pinned_mode(&mut self, messages: Vec<MessageInfo>) {
if !messages.is_empty() {
self.chat_state = ChatState::PinnedMessages {
messages,
selected_index: 0,
};
self.chat_state = ChatState::PinnedMessages { messages, selected_index: 0 };
}
}
@@ -118,11 +115,7 @@ impl<T: TdClientTrait> ModalMethods<T> for App<T> {
}
fn select_previous_pinned(&mut self) {
if let ChatState::PinnedMessages {
selected_index,
messages,
} = &mut self.chat_state
{
if let ChatState::PinnedMessages { selected_index, messages } = &mut self.chat_state {
if *selected_index + 1 < messages.len() {
*selected_index += 1;
}
@@ -138,11 +131,7 @@ impl<T: TdClientTrait> ModalMethods<T> for App<T> {
}
fn get_selected_pinned(&self) -> Option<&MessageInfo> {
if let ChatState::PinnedMessages {
messages,
selected_index,
} = &self.chat_state
{
if let ChatState::PinnedMessages { messages, selected_index } = &self.chat_state {
messages.get(*selected_index)
} else {
None
@@ -170,10 +159,7 @@ impl<T: TdClientTrait> ModalMethods<T> for App<T> {
}
fn select_previous_profile_action(&mut self) {
if let ChatState::Profile {
selected_action, ..
} = &mut self.chat_state
{
if let ChatState::Profile { selected_action, .. } = &mut self.chat_state {
if *selected_action > 0 {
*selected_action -= 1;
}
@@ -181,10 +167,7 @@ impl<T: TdClientTrait> ModalMethods<T> for App<T> {
}
fn select_next_profile_action(&mut self, max_actions: usize) {
if let ChatState::Profile {
selected_action, ..
} = &mut self.chat_state
{
if let ChatState::Profile { selected_action, .. } = &mut self.chat_state {
if *selected_action < max_actions.saturating_sub(1) {
*selected_action += 1;
}
@@ -192,41 +175,25 @@ impl<T: TdClientTrait> ModalMethods<T> for App<T> {
}
fn show_leave_group_confirmation(&mut self) {
if let ChatState::Profile {
leave_group_confirmation_step,
..
} = &mut self.chat_state
{
if let ChatState::Profile { leave_group_confirmation_step, .. } = &mut self.chat_state {
*leave_group_confirmation_step = 1;
}
}
fn show_leave_group_final_confirmation(&mut self) {
if let ChatState::Profile {
leave_group_confirmation_step,
..
} = &mut self.chat_state
{
if let ChatState::Profile { leave_group_confirmation_step, .. } = &mut self.chat_state {
*leave_group_confirmation_step = 2;
}
}
fn cancel_leave_group(&mut self) {
if let ChatState::Profile {
leave_group_confirmation_step,
..
} = &mut self.chat_state
{
if let ChatState::Profile { leave_group_confirmation_step, .. } = &mut self.chat_state {
*leave_group_confirmation_step = 0;
}
}
fn get_leave_group_confirmation_step(&self) -> u8 {
if let ChatState::Profile {
leave_group_confirmation_step,
..
} = &self.chat_state
{
if let ChatState::Profile { leave_group_confirmation_step, .. } = &self.chat_state {
*leave_group_confirmation_step
} else {
0
@@ -242,10 +209,7 @@ impl<T: TdClientTrait> ModalMethods<T> for App<T> {
}
fn get_selected_profile_action(&self) -> Option<usize> {
if let ChatState::Profile {
selected_action, ..
} = &self.chat_state
{
if let ChatState::Profile { selected_action, .. } = &self.chat_state {
Some(*selected_action)
} else {
None
@@ -277,11 +241,8 @@ impl<T: TdClientTrait> ModalMethods<T> for App<T> {
}
fn select_next_reaction(&mut self) {
if let ChatState::ReactionPicker {
selected_index,
available_reactions,
..
} = &mut self.chat_state
if let ChatState::ReactionPicker { selected_index, available_reactions, .. } =
&mut self.chat_state
{
if *selected_index + 1 < available_reactions.len() {
*selected_index += 1;
@@ -290,11 +251,8 @@ impl<T: TdClientTrait> ModalMethods<T> for App<T> {
}
fn get_selected_reaction(&self) -> Option<&String> {
if let ChatState::ReactionPicker {
available_reactions,
selected_index,
..
} = &self.chat_state
if let ChatState::ReactionPicker { available_reactions, selected_index, .. } =
&self.chat_state
{
available_reactions.get(*selected_index)
} else {

View File

@@ -2,8 +2,8 @@
//!
//! Handles chat list navigation and selection
use crate::app::{App, ChatState, InputMode};
use crate::app::methods::search::SearchMethods;
use crate::app::{App, ChatState, InputMode};
use crate::tdlib::TdClientTrait;
/// Navigation methods for chat list

View File

@@ -71,8 +71,7 @@ impl<T: TdClientTrait> SearchMethods<T> for App<T> {
fn get_filtered_chats(&self) -> Vec<&ChatInfo> {
// Используем ChatFilter для централизованной фильтрации
let mut criteria = ChatFilterCriteria::new()
.with_folder(self.selected_folder_id);
let mut criteria = ChatFilterCriteria::new().with_folder(self.selected_folder_id);
if !self.search_query.is_empty() {
criteria = criteria.with_search(self.search_query.clone());
@@ -113,12 +112,7 @@ impl<T: TdClientTrait> SearchMethods<T> for App<T> {
}
fn select_next_search_result(&mut self) {
if let ChatState::SearchInChat {
selected_index,
results,
..
} = &mut self.chat_state
{
if let ChatState::SearchInChat { selected_index, results, .. } = &mut self.chat_state {
if *selected_index + 1 < results.len() {
*selected_index += 1;
}
@@ -126,12 +120,7 @@ impl<T: TdClientTrait> SearchMethods<T> for App<T> {
}
fn get_selected_search_result(&self) -> Option<&MessageInfo> {
if let ChatState::SearchInChat {
results,
selected_index,
..
} = &self.chat_state
{
if let ChatState::SearchInChat { results, selected_index, .. } = &self.chat_state {
results.get(*selected_index)
} else {
None

View File

@@ -5,13 +5,13 @@
mod chat_filter;
mod chat_state;
mod state;
pub mod methods;
mod state;
pub use chat_filter::{ChatFilter, ChatFilterCriteria};
pub use chat_state::{ChatState, InputMode};
pub use state::AppScreen;
pub use methods::*;
pub use state::AppScreen;
use crate::accounts::AccountProfile;
use crate::tdlib::{ChatInfo, TdClient, TdClientTrait};
@@ -165,9 +165,7 @@ impl<T: TdClientTrait> App<T> {
let audio_cache_size_mb = config.audio.cache_size_mb;
#[cfg(feature = "images")]
let image_cache = Some(crate::media::cache::ImageCache::new(
config.images.cache_size_mb,
));
let image_cache = Some(crate::media::cache::ImageCache::new(config.images.cache_size_mb));
#[cfg(feature = "images")]
let inline_image_renderer = crate::media::image_renderer::ImageRenderer::new_fast();
#[cfg(feature = "images")]
@@ -275,11 +273,8 @@ impl<T: TdClientTrait> App<T> {
/// Navigate to next item in account switcher list.
pub fn account_switcher_select_next(&mut self) {
if let Some(AccountSwitcherState::SelectAccount {
accounts,
selected_index,
..
}) = &mut self.account_switcher
if let Some(AccountSwitcherState::SelectAccount { accounts, selected_index, .. }) =
&mut self.account_switcher
{
// +1 for the "Add account" item at the end
let max_index = accounts.len();
@@ -372,20 +367,6 @@ impl<T: TdClientTrait> App<T> {
.and_then(|id| self.chats.iter().find(|c| c.id == id))
}
// ========== Getter/Setter методы для инкапсуляции ==========
// Config