diff --git a/Cargo.lock b/Cargo.lock index af81d4c..7970579 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -294,9 +294,9 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ "event-listener", "event-listener-strategy", @@ -519,18 +519,18 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytemuck" -version = "1.23.1" +version = "1.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "441473f2b4b0459a68628c744bc61d23e730fb00128b841d30fa4bb3972257e4" +checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29" dependencies = [ "proc-macro2", "quote", @@ -577,9 +577,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.31" +version = "1.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" +checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e" dependencies = [ "jobserver", "libc", @@ -986,12 +986,13 @@ dependencies = [ [[package]] name = "egui-selectable-table" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e60f9b77832c217b08eb0f1a12f5e39d5a3bc93d6c7db49498ded94a51beb5" +checksum = "45fc2987e037c06872bf6889ca8ba5fd7baccd51d07ef4d0327fe37336511971" dependencies = [ "egui", "egui_extras", + "nucleo-matcher", "rayon", ] @@ -1220,9 +1221,9 @@ checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" [[package]] name = "event-listener" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -1350,9 +1351,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ "fastrand", "futures-core", @@ -1664,9 +1665,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ "atomic-waker", "bytes", @@ -1694,9 +1695,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "foldhash", ] @@ -2140,9 +2141,9 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" [[package]] name = "libc" -version = "0.2.174" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libloading" @@ -2307,7 +2308,7 @@ dependencies = [ "once_cell", "rustc-hash 1.1.0", "strum 0.26.3", - "thiserror 2.0.12", + "thiserror 2.0.14", "unicode-ident", ] @@ -2939,7 +2940,7 @@ checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1" dependencies = [ "base64", "indexmap", - "quick-xml 0.38.0", + "quick-xml 0.38.1", "serde", "time", ] @@ -2959,9 +2960,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee9b2fa7a4517d2c91ff5bc6c297a427a96749d15f98fcdbb22c05571a4d4b7" +checksum = "b5bd19146350fe804f7cb2669c851c03d69da628803dab0d98018142aaa5d829" dependencies = [ "cfg-if", "concurrent-queue", @@ -3013,9 +3014,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "d61789d7719defeb74ea5fe81f2fdfdbd28a803847077cecce2ff14e1472f6f1" dependencies = [ "unicode-ident", ] @@ -3047,9 +3048,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8927b0664f5c5a98265138b7e3f90aa19a6b21353182469ace36d4ac527b7b1b" +checksum = "9845d9dccf565065824e69f9f235fafba1587031eda353c1f1561cd6a6be78f4" dependencies = [ "memchr", ] @@ -3139,7 +3140,7 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3310,9 +3311,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -3477,9 +3478,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] @@ -3492,9 +3493,9 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "slab" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "slotmap" @@ -3684,7 +3685,7 @@ dependencies = [ [[package]] name = "talon-gui" -version = "1.2.0" +version = "1.3.0" dependencies = [ "chrono", "csv", @@ -3748,11 +3749,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "0b0949c3a6c842cbde3f1686d6eea5a010516deb7085f79db747562d4102f41e" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.14", ] [[package]] @@ -3768,9 +3769,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "cc5b44b4ab9c2fdd0e0512e6bece8388e214c0749f5862b114cc5b7a25daf227" dependencies = [ "proc-macro2", "quote", @@ -4399,7 +4400,7 @@ dependencies = [ "raw-window-handle", "rustc-hash 1.1.0", "smallvec", - "thiserror 2.0.12", + "thiserror 2.0.14", "wgpu-core-deps-windows-linux-android", "wgpu-hal", "wgpu-types", @@ -4429,7 +4430,7 @@ dependencies = [ "portable-atomic", "raw-window-handle", "renderdoc-sys", - "thiserror 2.0.12", + "thiserror 2.0.14", "wgpu-types", ] @@ -4443,7 +4444,7 @@ dependencies = [ "bytemuck", "js-sys", "log", - "thiserror 2.0.12", + "thiserror 2.0.14", "web-sys", ] @@ -5199,9 +5200,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke", "zerofrom", diff --git a/Cargo.toml b/Cargo.toml index 0bf6729..734c2ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "talon-gui" -version = "1.2.0" +version = "1.3.0" edition = "2024" authors = ["TheRustyPickle "] readme = "README.md" @@ -28,11 +28,11 @@ grammers-crypto = "=0.7.0" grammers-tl-gen = "=0.7.0" grammers-tl-types = "=0.7.0" grammers-mtsender = "=0.7.0" -tokio = { version = "1.47.0", features = ["rt-multi-thread"] } +tokio = { version = "1.47.1", features = ["rt-multi-thread"] } log = "0.4.27" pretty_env_logger = "0.5.0" serde = { version = "1.0.219", features = ["derive"] } -serde_json = "1.0.141" +serde_json = "1.0.142" dirs = "6.0.0" open = "5.3.2" reqwest = { version = "0.12.22", features = ["json"] } @@ -46,7 +46,7 @@ rayon = "1.10.0" csv = "1.3.1" strum = "0.27.2" strum_macros = "0.27.2" -egui-selectable-table = "0.3.0" +egui-selectable-table = { version = "0.4.1", features = ["fuzzy-matching"] } nucleo-matcher = "0.3.1" # The profile that 'cargo dist' will build with diff --git a/src/ui_components/initializer.rs b/src/ui_components/initializer.rs index d8861b6..aae854d 100644 --- a/src/ui_components/initializer.rs +++ b/src/ui_components/initializer.rs @@ -468,11 +468,11 @@ impl MainWindow { &mut self.counter.counts[ongoing] } - pub fn chart_all(&mut self) -> IterMut { + pub fn chart_all(&mut self) -> IterMut<'_, ChartsData> { self.chart.iter_mut() } - pub fn table_all(&mut self) -> IterMut { + pub fn table_all(&mut self) -> IterMut<'_, UserTableData> { self.table.iter_mut() } } diff --git a/src/ui_components/processor/date_handler.rs b/src/ui_components/processor/date_handler.rs index 6c8071d..d32a28d 100644 --- a/src/ui_components/processor/date_handler.rs +++ b/src/ui_components/processor/date_handler.rs @@ -26,25 +26,25 @@ impl DatePickerHandler { } /// Verify whether the current From and To dates have changed pub fn check_date_change(&mut self) -> bool { - if let Some(d) = self.last_from { - if d != self.from { - if self.from > self.to { - self.from = self.to; - } - - self.last_from = Some(self.from); - return true; + if let Some(d) = self.last_from + && d != self.from + { + if self.from > self.to { + self.from = self.to; } - } - if let Some(d) = self.last_to { - if d != self.to { - if self.to < self.from { - self.to = self.from; - } - self.last_to = Some(self.to); - return true; + self.last_from = Some(self.from); + return true; + } + if let Some(d) = self.last_to + && d != self.to + { + if self.to < self.from { + self.to = self.from; } + + self.last_to = Some(self.to); + return true; } false } diff --git a/src/ui_components/processor/parsed_chat.rs b/src/ui_components/processor/parsed_chat.rs index 10f904d..878e983 100644 --- a/src/ui_components/processor/parsed_chat.rs +++ b/src/ui_components/processor/parsed_chat.rs @@ -27,10 +27,10 @@ impl ParsedChat { } pub fn set_end_point(&mut self, point: i32) -> bool { - if let Some(start) = self.start_point { - if point >= start { - return false; - } + if let Some(start) = self.start_point + && point >= start + { + return false; } self.end_point = Some(point); true diff --git a/src/ui_components/processor/tg_comms.rs b/src/ui_components/processor/tg_comms.rs index 89cdd5e..2aa4c9f 100644 --- a/src/ui_components/processor/tg_comms.rs +++ b/src/ui_components/processor/tg_comms.rs @@ -344,7 +344,7 @@ impl MainWindow { let chart_name = to_chart_name(username.clone(), &full_name, user_id); for chart in self.chart_all() { - chart.clear_blacklisted(&[chart_name.clone()]); + chart.clear_blacklisted(std::slice::from_ref(&chart_name)); } for table in self.table_all() { diff --git a/src/ui_components/tab_ui/blacklist.rs b/src/ui_components/tab_ui/blacklist.rs index 22a1d49..c958c85 100644 --- a/src/ui_components/tab_ui/blacklist.rs +++ b/src/ui_components/tab_ui/blacklist.rs @@ -123,6 +123,7 @@ pub struct BlacklistData { target_username: String, failed_blacklist: i32, all_ids: HashSet, + search_query: String, } impl Default for BlacklistData { fn default() -> Self { @@ -134,12 +135,15 @@ impl Default for BlacklistData { .auto_scroll() .select_full_row() .serial_column() + .no_ctrl_a_capture() .auto_reload(1); + Self { table, target_username: String::new(), failed_blacklist: 0, all_ids: HashSet::new(), + search_query: String::new(), } } } @@ -280,9 +284,44 @@ then right click on User Table to blacklist", } }); - ui.add_space(40.0); + ui.add_space(20.0); ui.horizontal(|ui| { + let text_box = TextEdit::singleline(&mut self.blacklist.search_query) + .hint_text("Search by name, username or user ID"); + ui.add(text_box); + + if ui + .button("Search") + .on_hover_text("Filter rows that match the search query") + .clicked() + { + let search_query = self.blacklist.search_query.clone(); + + if search_query.is_empty() { + self.blacklist.table.recreate_rows(); + self.blacklist.search_query.clear(); + } else { + let column_list = vec![ColumnName::Name, ColumnName::Username, ColumnName::UserID]; + + self.blacklist + .table + .search_and_show(&column_list, &search_query, None, None); + } + + } + if ui + .button("Clear") + .on_hover_text("Clear search result") + .clicked() + { + self.blacklist.table.recreate_rows(); + self.blacklist.search_query.clear(); + } + + ui.separator(); + + if ui .button("Select All") .on_hover_text("Select all users. Also usable with CTRL + A. Use CTRL + mouse click for manual selection") @@ -309,6 +348,8 @@ then right click on User Table to blacklist", } }); + ui.separator(); + let column_size = (ui.available_width() - 20.0) / 3.0; self.blacklist.table.show_ui(ui, |table| { table diff --git a/src/ui_components/tab_ui/charts.rs b/src/ui_components/tab_ui/charts.rs index cada28c..43a7e6e 100644 --- a/src/ui_components/tab_ui/charts.rs +++ b/src/ui_components/tab_ui/charts.rs @@ -20,6 +20,8 @@ pub struct ChartsData { search_text: String, modal_open: bool, available_users: BTreeMap, + filtered_users: BTreeSet, + use_filtered_users: bool, chart_type: ChartType, last_chart_type: ChartType, chart_timing: ChartTiming, @@ -246,8 +248,8 @@ impl ChartsData { fn show_modal_popup(&mut self, ui: &mut Ui) { let response = Modal::new(Id::new("customize_view")).show(ui.ctx(), |ui| { - ui.set_width(300.0); - ui.set_height(300.0); + ui.set_width(400.0); + ui.set_height(350.0); TopBottomPanel::top("customize_top_view").show_inside(ui, |ui| { ui.vertical_centered(|ui| { ui.heading("Customize View"); @@ -265,35 +267,50 @@ impl ChartsData { }); CentralPanel::default().show_inside(ui, |ui| { - let text_edit = - TextEdit::singleline(&mut self.search_text).hint_text("Search user"); + ui.horizontal(|ui| { + let text_edit = + TextEdit::singleline(&mut self.search_text).hint_text("Search user"); - ui.add(text_edit); + ui.add(text_edit); - ScrollArea::vertical().show(ui, |ui| { - let all_keys = self.available_users.keys().cloned().collect::>(); + if ui.button("Search").clicked() { + self.use_filtered_users = true; + self.filtered_users.clear(); - if self.search_text.is_empty() { - for val in all_keys { - ui.horizontal(|ui| { - ui.checkbox(self.available_users.get_mut(&val).unwrap(), val); - ui.allocate_space(ui.available_size()); - }); - } - } else { + let all_keys = self.available_users.keys().cloned().collect::>(); let pattern = Pattern::parse( &self.search_text, CaseMatching::Ignore, Normalization::Smart, ); - let matches = pattern.match_list(all_keys.iter(), &mut self.matcher); + let matches = pattern.match_list(all_keys, &mut self.matcher); for (val, _) in matches { + self.filtered_users.insert(val); + } + } + + if ui.button("Clear").clicked() { + self.use_filtered_users = false; + } + }); + + ScrollArea::vertical().show(ui, |ui| { + if self.use_filtered_users { + for val in &self.filtered_users { ui.horizontal(|ui| { ui.checkbox(self.available_users.get_mut(val).unwrap(), val); ui.allocate_space(ui.available_size()); }); } + } else { + let all_keys = self.available_users.keys().cloned().collect::>(); + for val in all_keys { + ui.horizontal(|ui| { + ui.checkbox(self.available_users.get_mut(&val).unwrap(), val); + ui.allocate_space(ui.available_size()); + }); + } } }); }); @@ -967,26 +984,25 @@ impl MainWindow { .width(1.0) .name(whitelist_data_name); - if show_total_message { - if let Some(total_message_bars) = bar_list.remove("Show total data") { - let total_message_chart = - BarChart::new("Total message", total_message_bars) - .width(1.0) - .name(total_data_name); - - whitelist_chart = whitelist_chart.stack_on(&[&total_message_chart]); - all_charts.push(total_message_chart); - } + if show_total_message + && let Some(total_message_bars) = bar_list.remove("Show total data") + { + let total_message_chart = BarChart::new("Total message", total_message_bars) + .width(1.0) + .name(total_data_name); + + whitelist_chart = whitelist_chart.stack_on(&[&total_message_chart]); + all_charts.push(total_message_chart); } all_charts.push(whitelist_chart); } - } else if show_total_message { - if let Some(total_message_bars) = bar_list.remove("Show total data") { - let total_message_chart = BarChart::new("Total message", total_message_bars) - .width(1.0) - .name(total_data_name); - all_charts.push(total_message_chart); - } + } else if show_total_message + && let Some(total_message_bars) = bar_list.remove("Show total data") + { + let total_message_chart = BarChart::new("Total message", total_message_bars) + .width(1.0) + .name(total_data_name); + all_charts.push(total_message_chart); } // User data stacking only happens on Message chart diff --git a/src/ui_components/tab_ui/counter.rs b/src/ui_components/tab_ui/counter.rs index 453a4a2..511810c 100644 --- a/src/ui_components/tab_ui/counter.rs +++ b/src/ui_components/tab_ui/counter.rs @@ -360,7 +360,7 @@ Login to one or more accounts multiple times with different session names!", |i| LIMIT_SELECTION[i], ) .on_hover_text( - "When counting how many messages to count in each frame load? Default: 20 + "When counting how many messages to count in each frame load? Default: 100 Higher can increase the counting speed but flood wait will also be more visible in the UI. diff --git a/src/ui_components/tab_ui/user_table.rs b/src/ui_components/tab_ui/user_table.rs index 41cbcf5..dddf8d3 100644 --- a/src/ui_components/tab_ui/user_table.rs +++ b/src/ui_components/tab_ui/user_table.rs @@ -1,5 +1,5 @@ use chrono::{NaiveDate, NaiveDateTime}; -use eframe::egui::{Align, Button, ComboBox, Key, Layout, Response, RichText, Sense, Ui}; +use eframe::egui::{Align, Button, ComboBox, Key, Layout, Response, RichText, Sense, TextEdit, Ui}; use egui_extras::{Column, DatePickerButton}; use egui_selectable_table::{ ColumnOperations, ColumnOrdering, SelectableRow, SelectableTable, SortOrder, @@ -24,6 +24,7 @@ pub struct Config { whitelist_rows: bool, blacklisted_rows: bool, copy_selected: bool, + select_all_rows: bool, } #[derive(Clone, Serialize)] @@ -124,6 +125,7 @@ impl ColumnOperations for ColumnName { .on_hover_text(hover_text); Some(response) } + fn create_table_row( &self, ui: &mut Ui, @@ -182,6 +184,10 @@ impl ColumnOperations for ColumnName { table.config.blacklisted_rows = true; ui.close(); } + if ui.button("Select all rows").clicked() { + table.config.select_all_rows = true; + ui.close(); + } }); label } @@ -278,6 +284,7 @@ pub struct UserTableData { total_message: u32, total_whitelisted_message: u32, reload_count: u8, + search_query: String, } impl Default for UserTableData { @@ -285,7 +292,9 @@ impl Default for UserTableData { let table = SelectableTable::new(ColumnName::iter().collect()) .auto_scroll() .serial_column() - .horizontal_scroll(); + .horizontal_scroll() + .no_ctrl_a_capture(); + Self { user_data: HashMap::new(), table, @@ -294,6 +303,7 @@ impl Default for UserTableData { total_message: 0, total_whitelisted_user: 0, reload_count: 0, + search_query: String::new(), } } } @@ -619,6 +629,46 @@ impl MainWindow { }); }); + ui.separator(); + + ui.add_enabled_ui(date_enabled, |ui| { + ui.horizontal(|ui| { + let text_box = TextEdit::singleline(&mut self.table().search_query) + .hint_text("Search by name, username or user ID"); + ui.add(text_box); + + if ui + .button("Search") + .on_hover_text("Filter rows that match the search query") + .clicked() + { + if self.table().search_query.is_empty() { + self.table().table.recreate_rows(); + self.table().search_query.clear(); + } else { + let column_list = + vec![ColumnName::Name, ColumnName::Username, ColumnName::UserID]; + + let search_query = self.table_i().search_query.clone(); + + self.table() + .table + .search_and_show(&column_list, &search_query, None, None); + } + } + if ui + .button("Clear") + .on_hover_text("Clear search result") + .clicked() + { + self.table().table.recreate_rows(); + self.table().search_query.clear(); + } + }); + }); + + ui.separator(); + // Monitor for H and L key presses if date_enabled { let is_ctrl_pressed = ui.ctx().input(|i| i.modifiers.ctrl); @@ -646,6 +696,7 @@ impl MainWindow { let to_whitelist_selected = self.table().table.config.whitelist_rows; let to_blacklist_selected = self.table().table.config.blacklisted_rows; let to_copy = self.table().table.config.copy_selected; + let to_select_all = self.table().table.config.select_all_rows; if to_whitelist_selected { self.table().table.config.whitelist_rows = false; @@ -662,6 +713,11 @@ impl MainWindow { self.copy_selected_cells(ui); } + if to_select_all { + self.table().table.config.select_all_rows = false; + self.table().table.select_all(); + } + self.table().table.show_ui(ui, |builder| { let mut table = builder .striped(true) diff --git a/src/ui_components/tab_ui/whitelist.rs b/src/ui_components/tab_ui/whitelist.rs index c2c4d1a..e847508 100644 --- a/src/ui_components/tab_ui/whitelist.rs +++ b/src/ui_components/tab_ui/whitelist.rs @@ -124,6 +124,7 @@ pub struct WhitelistData { target_username: String, failed_whitelist: i32, all_ids: HashSet, + search_query: String, } impl Default for WhitelistData { @@ -136,12 +137,14 @@ impl Default for WhitelistData { .auto_scroll() .select_full_row() .serial_column() + .no_ctrl_a_capture() .auto_reload(1); Self { table, target_username: String::new(), failed_whitelist: 0, all_ids: HashSet::new(), + search_query: String::new(), } } } @@ -286,9 +289,44 @@ then right click on User Table to whitelist", } }); - ui.add_space(40.0); + ui.add_space(20.0); + + let column_size = (ui.available_width() - 20.0) / 3.0; ui.horizontal(|ui| { + let text_box = TextEdit::singleline(&mut self.whitelist.search_query) + .hint_text("Search by name, username or user ID"); + ui.add(text_box); + + if ui + .button("Search") + .on_hover_text("Filter rows that match the search query") + .clicked() + { + let search_query = self.whitelist.search_query.clone(); + + if search_query.is_empty() { + self.whitelist.table.recreate_rows(); + self.whitelist.search_query.clear(); + } else { + let column_list = vec![ColumnName::Name, ColumnName::Username, ColumnName::UserID]; + + self.whitelist + .table + .search_and_show(&column_list, &search_query, None, None); + } + } + if ui + .button("Clear") + .on_hover_text("Clear search result") + .clicked() + { + self.whitelist.table.recreate_rows(); + self.whitelist.search_query.clear(); + } + + ui.separator(); + if ui .button("Select All") .on_hover_text("Select all users. Also usable with CTRL + A. Use CTRL + mouse click for manual selection") @@ -321,7 +359,7 @@ then right click on User Table to whitelist", } }); - let column_size = (ui.available_width() - 20.0) / 3.0; + ui.separator(); self.whitelist.table.show_ui(ui, |table| { table .striped(true) diff --git a/src/utils.rs b/src/utils.rs index e0145d8..bcec691 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -25,11 +25,11 @@ pub fn find_session_files() -> Vec { let mut sessions = Vec::new(); if let Ok(entries) = fs::read_dir(".") { for entry in entries { - if let Ok(file_name) = entry.unwrap().file_name().into_string() { - if file_name.ends_with(".session") { - info!("Found existing session file {file_name}"); - sessions.push(file_name); - } + if let Ok(file_name) = entry.unwrap().file_name().into_string() + && file_name.ends_with(".session") + { + info!("Found existing session file {file_name}"); + sessions.push(file_name); } } } @@ -202,10 +202,11 @@ pub fn get_api_keys() -> Option { .expect("Failed to read file"); let result = serde_json::from_str::(&contents); - if let Ok(result) = result { - if !result.api_id.is_empty() && !result.api_hash.is_empty() { - to_return = Some(result); - } + if let Ok(result) = result + && !result.api_id.is_empty() + && !result.api_hash.is_empty() + { + to_return = Some(result); } } @@ -267,14 +268,12 @@ pub fn save_whitelisted_users(packed_chats: Vec, overwrit let file = File::open(&whitelist_path); - if !overwrite { - if let Ok(mut file) = file { - let mut contents = String::new(); - file.read_to_string(&mut contents) - .expect("Failed to read file"); + if !overwrite && let Ok(mut file) = file { + let mut contents = String::new(); + file.read_to_string(&mut contents) + .expect("Failed to read file"); - existing_data = serde_json::from_str(&contents).unwrap(); - } + existing_data = serde_json::from_str(&contents).unwrap(); } existing_data.extend(packed_chats); @@ -295,14 +294,12 @@ pub fn save_blacklisted_users(packed_chats: Vec, overwrit let file = File::open(&whitelist_path); - if !overwrite { - if let Ok(mut file) = file { - let mut contents = String::new(); - file.read_to_string(&mut contents) - .expect("Failed to read file"); + if !overwrite && let Ok(mut file) = file { + let mut contents = String::new(); + file.read_to_string(&mut contents) + .expect("Failed to read file"); - existing_data = serde_json::from_str(&contents).unwrap(); - } + existing_data = serde_json::from_str(&contents).unwrap(); } existing_data.extend(packed_chats);