Skip to main content

modde_ui/views/
data_tab.rs

1use iced::widget::{button, checkbox, column, container, row, scrollable, text, text_input};
2use iced::{Alignment, Element, Length};
3
4use crate::app::Message;
5
6/// State for the data tab view.
7#[derive(Debug, Clone, Default)]
8pub struct DataTabState {
9    pub filter: String,
10    pub show_conflicts_only: bool,
11}
12
13/// Render the data tab view showing file-level conflict details.
14pub fn view<'a>(
15    state: &'a DataTabState,
16    conflict_files: &'a [(String, Vec<String>)],
17) -> Element<'a, Message> {
18    let title_bar = row![
19        text("Data Files").size(20),
20        iced::widget::space::horizontal(),
21    ]
22    .align_y(Alignment::Center);
23
24    let toolbar = row![
25        text_input("Filter files...", &state.filter)
26            .on_input(Message::DataTabFilterChanged)
27            .padding(6)
28            .width(Length::Fill),
29        checkbox(state.show_conflicts_only)
30            .on_toggle(Message::DataTabToggleConflicts),
31        text("Conflicts only").size(13),
32    ]
33    .spacing(8)
34    .align_y(Alignment::Center);
35
36    let filter_lower = state.filter.to_lowercase();
37    let filtered: Vec<&(String, Vec<String>)> = conflict_files
38        .iter()
39        .filter(|(file, _)| {
40            if !filter_lower.is_empty() && !file.to_lowercase().contains(&filter_lower) {
41                return false;
42            }
43            if state.show_conflicts_only {
44                return true; // all entries in conflict_files are conflicts
45            }
46            true
47        })
48        .collect();
49
50    let file_count = filtered.len();
51
52    let file_rows: Element<Message> = if filtered.is_empty() {
53        container(
54            text("No data files to display.").size(14),
55        )
56        .padding(20)
57        .width(Length::Fill)
58        .center_x(Length::Fill)
59        .into()
60    } else {
61        let rows = filtered
62            .into_iter()
63            .fold(column![].spacing(4), |col, (file, providers)| {
64                let provider_list = providers.join(", ");
65                let file_row = row![
66                    text(file).size(13).width(Length::Fill),
67                    text(provider_list).size(12).width(Length::Fixed(300.0)),
68                ]
69                .spacing(8)
70                .padding([4, 8]);
71                col.push(file_row)
72            });
73
74        scrollable(rows).height(Length::Fill).into()
75    };
76
77    let header = row![
78        text("File Path").size(12).width(Length::Fill),
79        text("Providing Mods").size(12).width(Length::Fixed(300.0)),
80    ]
81    .spacing(8)
82    .padding([4, 8]);
83
84    let status = text(format!("{file_count} file(s) shown")).size(12);
85
86    column![
87        title_bar,
88        toolbar,
89        header,
90        iced::widget::rule::horizontal(1),
91        file_rows,
92        status,
93    ]
94    .spacing(8)
95    .padding(16)
96    .width(Length::Fill)
97    .height(Length::Fill)
98    .into()
99}