mirror of
https://github.com/flectar/mail.git
synced 2026-11-11 17:57:54 +00:00
527 lines
14 KiB
Plaintext
527 lines
14 KiB
Plaintext
// Shared UI-facing data types live outside app.slint so feature components can
|
|
// consume the same models without depending on the application window.
|
|
import "../resources/fonts/noto-emoji/NotoEmoji[wght].ttf";
|
|
|
|
export struct LocalizedMessage {
|
|
key: string,
|
|
argument: string,
|
|
second_argument: string,
|
|
third_argument: string,
|
|
}
|
|
|
|
// Computed only while the Storage settings page is open. `offset` and
|
|
// `fraction` let the view paint one proportional bar without doing byte math
|
|
// in Slint's 32-bit integer type.
|
|
export struct StorageUsageRow {
|
|
kind: string,
|
|
size: string,
|
|
fraction: float,
|
|
offset: float,
|
|
color: color,
|
|
}
|
|
|
|
// Drag payloads are opaque to Slint and stay application-internal. Keeping
|
|
// the transfer construction, validation, and mutation on one shared global
|
|
// lets the list and every responsive sidebar use the same DnD contract.
|
|
export global MailDragApi {
|
|
pure callback make-transfer(int, int) -> data-transfer;
|
|
pure callback can-drop-on-mailbox(data-transfer, string, int, int) -> bool;
|
|
callback drop-on-mailbox(data-transfer, string, int, int) -> bool;
|
|
}
|
|
|
|
export struct MailboxRow {
|
|
account_id: int,
|
|
folder_id: int,
|
|
parent_folder_id: int,
|
|
depth: int,
|
|
has_children: bool,
|
|
expanded: bool,
|
|
is_standard: bool,
|
|
is_selectable: bool,
|
|
can_create_children: bool,
|
|
can_rename: bool,
|
|
can_delete: bool,
|
|
label_has_emoji: bool,
|
|
label: string,
|
|
scope: string,
|
|
context: string,
|
|
detail: string,
|
|
avatar: string,
|
|
avatar_image: image,
|
|
has_avatar: bool,
|
|
is_account: bool,
|
|
count: string,
|
|
color: color,
|
|
has_custom_color: bool,
|
|
}
|
|
|
|
// Provider labels and local auto-categories share one presentation model.
|
|
// `applied` is projected for the currently selected thread so menus and chips
|
|
// update from the same source of truth after every action.
|
|
export struct MailLabelRow {
|
|
id: int,
|
|
account_id: int,
|
|
account_name: string,
|
|
name: string,
|
|
display_name: string,
|
|
depth: int,
|
|
has_children: bool,
|
|
expanded: bool,
|
|
can_create_children: bool,
|
|
name_has_emoji: bool,
|
|
color: color,
|
|
applied: bool,
|
|
is_auto: bool,
|
|
is_global: bool,
|
|
// Unread mail the label's list shows, as the sidebar badge shows it.
|
|
count: string,
|
|
}
|
|
|
|
// One visible navigation entry per list row; stable keys also identify sections.
|
|
export enum SidebarRowKind {
|
|
unified-heading, unified-section, unified-inbox, unified-mailbox,
|
|
categories-section, important, other, category,
|
|
global-labels-section, global-label,
|
|
accounts-heading, account, folder, account-labels-section, account-label,
|
|
new-folder, new-label,
|
|
}
|
|
|
|
export struct SidebarRow {
|
|
key: string,
|
|
kind: SidebarRowKind,
|
|
mailbox: MailboxRow,
|
|
label: MailLabelRow,
|
|
open: bool,
|
|
show_row: bool,
|
|
reveal_row: bool,
|
|
}
|
|
|
|
// A file shown on a message-list row.
|
|
export struct ListAttachment {
|
|
id: string,
|
|
// The name before its extension, which stays whole when the name is cut.
|
|
stem: string,
|
|
extension: string,
|
|
// The file's type, as for MailAttachment.
|
|
kind: string,
|
|
previewable: bool,
|
|
}
|
|
|
|
export struct EmailRow {
|
|
id: int,
|
|
account_id: int,
|
|
account: string,
|
|
account_color: color,
|
|
account_profile: string,
|
|
show_account_marker: bool,
|
|
folder: string,
|
|
sender: string,
|
|
address: string,
|
|
initials: string,
|
|
favicon: image,
|
|
favicon_small: image,
|
|
has_favicon: bool,
|
|
subject: string,
|
|
preview: string,
|
|
time: string,
|
|
unread: bool,
|
|
starred: bool,
|
|
has_attachments: bool,
|
|
has_replied: bool,
|
|
message_count: int,
|
|
label_summary: string,
|
|
labels: [MailLabelRow],
|
|
// Gmail labels are tags; other accounts file labels like folders.
|
|
account_uses_labels: bool,
|
|
// The one-time code the message asks its reader to enter, if any, and
|
|
// the same code spelled out for screen readers.
|
|
verification_code: string,
|
|
verification_code_spelled: string,
|
|
// The conversation's first file, and how many files it holds.
|
|
attachment: ListAttachment,
|
|
attachment_total: int,
|
|
selected: bool,
|
|
checked: bool,
|
|
}
|
|
|
|
// Section controls and messages share a virtualized ListView. Closing rows
|
|
// stay in the model briefly at zero height so the accordion can settle.
|
|
export struct MailListEntry {
|
|
is_header: bool,
|
|
group_key: string,
|
|
group_kind: string,
|
|
group_count: int,
|
|
expanded: bool,
|
|
show_row: bool,
|
|
reveal_row: bool,
|
|
email_index: int,
|
|
email: EmailRow,
|
|
}
|
|
|
|
// Resolve keyboard movement against the entire model, including messages
|
|
// outside the virtualized viewport. Geometry stays in the Slint component.
|
|
export struct MailNavigationTarget {
|
|
id: int,
|
|
entry_index: int,
|
|
preceding_headers: int,
|
|
preceding_messages: int,
|
|
checked: bool,
|
|
}
|
|
|
|
export global MailListNavigation {
|
|
pure callback target([MailListEntry], int, string, int) -> MailNavigationTarget;
|
|
}
|
|
|
|
export struct MailProfileRow {
|
|
id: string,
|
|
name: string,
|
|
color: color,
|
|
account_count: int,
|
|
}
|
|
|
|
// An account in the profile editor's checklist; checked accounts belong to
|
|
// the profile being edited.
|
|
export struct ProfileMemberRow {
|
|
id: int,
|
|
name: string,
|
|
email: string,
|
|
initials: string,
|
|
avatar: image,
|
|
has_avatar: bool,
|
|
// The other profile the account is in now; empty when none.
|
|
other_profile: string,
|
|
checked: bool,
|
|
}
|
|
|
|
// Messages remain separate inside a conversation. The native side keeps the
|
|
// bodies and renderer state; this lightweight model is safe to virtualize even
|
|
// for long threads.
|
|
export struct ThreadMessageRow {
|
|
index: int,
|
|
sender: string,
|
|
address: string,
|
|
initials: string,
|
|
favicon: image,
|
|
favicon_small: image,
|
|
has_favicon: bool,
|
|
preview: string,
|
|
time: string,
|
|
to: string,
|
|
unread: bool,
|
|
outgoing: bool,
|
|
body_pending: bool,
|
|
selected: bool,
|
|
}
|
|
|
|
// A calendar server an account syncs; mirrors
|
|
// flectar_mail_core::models::CalendarConnection.
|
|
export struct CalendarConnectionRow {
|
|
id: int,
|
|
// google | generic | microsoft
|
|
kind: string,
|
|
base_url: string,
|
|
host: string,
|
|
username: string,
|
|
// The calendar's name when the connection syncs exactly one.
|
|
calendar_name: string,
|
|
calendar_count: int,
|
|
enabled: bool,
|
|
// "needs_reauth", "offline" or an error message; empty while it syncs.
|
|
error: string,
|
|
}
|
|
|
|
export struct AccountRow {
|
|
id: int,
|
|
drag_key: string,
|
|
name: string,
|
|
email: string,
|
|
provider: string,
|
|
mail_protocol: string,
|
|
status: string,
|
|
sync_error: string,
|
|
initials: string,
|
|
avatar: image,
|
|
avatar_small: image,
|
|
has_avatar: bool,
|
|
profile_id: string,
|
|
profile_name: string,
|
|
profile_color: color,
|
|
has_profile: bool,
|
|
has_account_color: bool,
|
|
username: string,
|
|
jmap_url: string,
|
|
incoming_security: string,
|
|
smtp_security: string,
|
|
trusted_certificate_pem: string,
|
|
incoming_host: string,
|
|
incoming_port: string,
|
|
smtp_host: string,
|
|
smtp_port: string,
|
|
mail_history: string,
|
|
sent_copy_policy: string,
|
|
keep_on_server: string,
|
|
// Days a POP3 server keeps downloaded mail on its own; -1 when it
|
|
// keeps it or hasn't said.
|
|
server_keeps_mail_days: int,
|
|
// Calendar servers the account syncs: its provider's first, then CalDAV.
|
|
calendar_connections: [CalendarConnectionRow],
|
|
// Gmail and Outlook accounts sync their provider's calendar at most once.
|
|
provider_calendar_connected: bool,
|
|
// Why connecting the provider's calendar last failed.
|
|
provider_calendar_error: string,
|
|
carddav_connected: bool,
|
|
carddav_enabled: bool,
|
|
carddav_status: string,
|
|
carddav_url: string,
|
|
carddav_username: string,
|
|
}
|
|
|
|
export struct EmailLink {
|
|
x: float,
|
|
y: float,
|
|
width: float,
|
|
height: float,
|
|
url: string,
|
|
name: string
|
|
}
|
|
|
|
// Email HTML is rasterized into bounded vertical tiles. Coordinates are
|
|
// normalized against the reading-pane width so HiDPI scaling stays in Slint
|
|
// and no single full-message bitmap has to move on every scroll frame.
|
|
export struct EmailTile {
|
|
image: image,
|
|
y: float,
|
|
height: float,
|
|
}
|
|
|
|
// The composer uses the same bounded-tile strategy as the message renderer,
|
|
// but these coordinates are logical pixels because cosmic-text owns the
|
|
// editor's exact wrapping and caret geometry.
|
|
export struct ComposeEditorTile {
|
|
image: image,
|
|
y: float,
|
|
height: float,
|
|
}
|
|
|
|
export struct EmailTemplateRow {
|
|
id: int,
|
|
name: string,
|
|
shortcut: string,
|
|
subject: string,
|
|
body_text: string,
|
|
}
|
|
|
|
export struct CalendarDay {
|
|
day: string,
|
|
iso_date: string,
|
|
date_label: string,
|
|
outside_month: bool,
|
|
is_today: bool,
|
|
is_selected: bool,
|
|
has_events: bool,
|
|
}
|
|
|
|
export struct CalendarWeekDay {
|
|
weekday: string,
|
|
day: string,
|
|
iso_date: string,
|
|
date_label: string,
|
|
is_today: bool,
|
|
}
|
|
|
|
export struct CalendarEventRow {
|
|
id: int,
|
|
editable: bool,
|
|
title: string,
|
|
detail: string,
|
|
iso_date: string,
|
|
date_label: string,
|
|
day_index: int,
|
|
month_index: int,
|
|
start_minutes: int,
|
|
duration_minutes: int,
|
|
color_index: int,
|
|
all_day: bool,
|
|
provider: string,
|
|
account: string,
|
|
calendar: string,
|
|
location: string,
|
|
organizer: string,
|
|
description: string,
|
|
attendees: string,
|
|
join_url: string,
|
|
rsvp_status: string,
|
|
recurrence: string,
|
|
status: string,
|
|
source: string,
|
|
}
|
|
|
|
// A flat model lets ListView virtualize individual events, including busy days.
|
|
export struct CalendarAgendaRow {
|
|
key: string,
|
|
kind: string,
|
|
iso_date: string,
|
|
date_label: string,
|
|
is_today: bool,
|
|
count: int,
|
|
time_label: string,
|
|
end_label: string,
|
|
offset: float,
|
|
previous_event: int,
|
|
next_event: int,
|
|
event: CalendarEventRow,
|
|
}
|
|
|
|
export struct CalendarAgendaFilterRow {
|
|
id: int,
|
|
name: string,
|
|
account: string,
|
|
color_index: int,
|
|
checked: bool,
|
|
}
|
|
|
|
// Provider calendar collections are kept separate from events so the
|
|
// calendar sidebar can mirror mail's account-aware navigation without
|
|
// inventing local placeholder rows.
|
|
export struct CalendarSourceRow {
|
|
id: int,
|
|
account_id: int,
|
|
group_start: bool,
|
|
name: string,
|
|
account_name: string,
|
|
email: string,
|
|
provider: string,
|
|
color: string,
|
|
color_index: int,
|
|
read_only: bool,
|
|
enabled: bool,
|
|
is_default: bool,
|
|
last_synced: string,
|
|
}
|
|
|
|
// Compose attachments intentionally expose display metadata only. Absolute
|
|
// paths stay in Rust so the UI cannot accidentally render or persist local
|
|
// filesystem details in a message.
|
|
export struct ComposeAttachment {
|
|
name: string,
|
|
detail: string,
|
|
}
|
|
|
|
// A deliberately small contact shape for compose autocomplete. The core
|
|
// keeps affinity/account scoping private and only exposes what the menu needs.
|
|
export struct ComposeContact {
|
|
name: string,
|
|
email: string,
|
|
initials: string,
|
|
}
|
|
|
|
// Mirrors flectar_mail_core::models::ContactSync.
|
|
export enum ContactSyncState { local, detached, synced, pending, conflict, unavailable, failed }
|
|
|
|
export struct ContactValueRow {
|
|
key: string,
|
|
value: string,
|
|
label: string,
|
|
preference: int,
|
|
}
|
|
|
|
export struct ContactRow {
|
|
avatar: image,
|
|
has-avatar: bool,
|
|
source: string,
|
|
id: int,
|
|
name: string,
|
|
email: string,
|
|
initials: string,
|
|
avatar_tone: int,
|
|
company: string,
|
|
detail: string,
|
|
last_contacted: string,
|
|
favorite: bool,
|
|
suggested: bool,
|
|
selected: bool,
|
|
}
|
|
|
|
// Account-aware contact navigation is projected separately from ContactRow so
|
|
// list rows stay small and the sidebar can update counts independently.
|
|
export struct ContactAccountRow {
|
|
id: int,
|
|
name: string,
|
|
email: string,
|
|
initials: string,
|
|
avatar: image,
|
|
has_avatar: bool,
|
|
count: string,
|
|
selected: bool,
|
|
}
|
|
|
|
export enum ContactSidebarRowKind { unified-heading, unified-section, all, favorites, suggestions, accounts-heading, account, contacts, hint }
|
|
export struct ContactSidebarRow {
|
|
key: string,
|
|
kind: ContactSidebarRowKind,
|
|
account: ContactAccountRow,
|
|
open: bool,
|
|
}
|
|
|
|
// Email document controls are shared directly with the native renderer.
|
|
export struct ReaderItem { name: string, url: string, kind: string, y: float }
|
|
export struct ReaderImage { x: float, y: float, width: float, height: float, alt: string, state: string }
|
|
export struct ReaderCaret { x: float, y: float, height: float, valid: bool }
|
|
export global EmailReader {
|
|
in-out property <bool> available: false;
|
|
in-out property <bool> body-pending: false;
|
|
in-out property <ReaderCaret> selection-start;
|
|
in-out property <ReaderCaret> selection-end;
|
|
in-out property <[ReaderImage]> images;
|
|
in-out property <int> revision: -1;
|
|
in-out property <int> message-id: -1;
|
|
callback ensure-body(int);
|
|
callback retry-images();
|
|
in-out property <int> failed-images;
|
|
pure callback link-at(float, float) -> string;
|
|
callback command(string);
|
|
callback find(string, int);
|
|
in-out property <bool> auto-fit: true;
|
|
in-out property <float> zoom: 1;
|
|
in-out property <int> zoom-revision: 0;
|
|
in-out property <float> width-ratio: 1;
|
|
in-out property <string> destination;
|
|
in-out property <string> context-link;
|
|
in-out property <string> query;
|
|
in-out property <string> find-status;
|
|
in-out property <string> notice;
|
|
in-out property <bool> find-open: false;
|
|
in-out property <bool> reader-mode: false;
|
|
in-out property <bool> caret-mode: false;
|
|
in-out property <[ReaderItem]> items;
|
|
in-out property <string> authored-text;
|
|
in-out property <bool> use-authored-text: false;
|
|
}
|
|
|
|
export struct MailAttachment {
|
|
id: string,
|
|
name: string,
|
|
detail: string,
|
|
previewable: bool,
|
|
// pdf, document, spreadsheet, presentation, image, video, audio,
|
|
// archive, code, calendar or file.
|
|
kind: string,
|
|
thumbnail: image,
|
|
has_thumbnail: bool,
|
|
}
|
|
export global MailAttachments {
|
|
callback deliver();
|
|
in-out property <[MailAttachment]> rows;
|
|
in-out property <bool> open: false;
|
|
in-out property <bool> busy: false;
|
|
in-out property <string> name;
|
|
in-out property <string> status;
|
|
in-out property <image> image;
|
|
in-out property <string> text;
|
|
in-out property <bool> is-image: false;
|
|
in-out property <int> page: 0;
|
|
in-out property <int> pages: 0;
|
|
in-out property <int> revision: 0;
|
|
callback command(string, string);
|
|
}
|