presentation/QuickContactActions.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <QHash> | ||
| 4 | #include <QObject> | ||
| 5 | #include <QPair> | ||
| 6 | #include <QSet> | ||
| 7 | #include <QVariantList> | ||
| 8 | #include <QUrl> | ||
| 9 | #include <QVariantMap> | ||
| 10 | #include <functional> | ||
| 11 | |||
| 12 | #include "data/ContactModels.h" | ||
| 13 | |||
| 14 | class ContactSyncCoordinator; | ||
| 15 | class QuickContactModel; | ||
| 16 | |||
| 17 | // Contact write entry points for QML (Sprint 97 S97.1.4/S97.1.7/S97.1.8, | ||
| 18 | // D-8, D-14; keeps QuickPimBackend small). Every call takes card keys | ||
| 19 | // ("<bookId>/<uid>"), never row indices. Writes go through the session's | ||
| 20 | // ContactOutbox (local first); the model updates the affected rows. | ||
| 21 | // | ||
| 22 | // Delete, move and edit leave an undo step (D-8: no confirmation for one | ||
| 23 | // contact; Ctrl+Z / the toast's Undo within the session). | ||
| 24 | class QuickContactActions final : public QObject { | ||
| 25 | 2335 | Q_OBJECT | |
| 26 | // Text of the step Undo would revert ("" = nothing to undo). | ||
| 27 | Q_PROPERTY(QString undoText READ undoText NOTIFY undoChanged) | ||
| 28 | // D-5: contacts that exist only on this computer and wait for a choice. | ||
| 29 | Q_PROPERTY(int localOnlyCount READ localOnlyCount NOTIFY booksChanged) | ||
| 30 | // D-14: the book a new contact goes to when no book is being viewed. | ||
| 31 | Q_PROPERTY(qint64 lastUsedBookId READ lastUsedBookId NOTIFY booksChanged) | ||
| 32 | Q_PROPERTY(bool collectAddresses READ collectAddresses WRITE setCollectAddresses NOTIFY settingsChanged) | ||
| 33 | // Sprint 103 D-6: the card that is the user ("" when none is set or it is | ||
| 34 | // gone). Per profile (QSettings contacts/meCard), never synced. | ||
| 35 | Q_PROPERTY(QString meKey READ meKey NOTIFY meChanged) | ||
| 36 | public: | ||
| 37 | using CoordinatorProvider = std::function<ContactSyncCoordinator *()>; | ||
| 38 | QuickContactActions(CoordinatorProvider coordinator, QuickContactModel &model, QObject *parent = nullptr); | ||
| 39 | |||
| 40 | // {ok, key} or {ok: false, error, errors: {field: message}, duplicates: | ||
| 41 | // [{key, name, book}]} — S97.1.8: an address another card of the same | ||
| 42 | // book already uses is reported (never blocking: pass force: true). | ||
| 43 | Q_INVOKABLE QVariantMap save(const QString &key, const QVariantMap &fields, bool force = false); | ||
| 44 | Q_INVOKABLE QVariantMap create(qint64 bookId, const QVariantMap &fields, bool force = false); | ||
| 45 | Q_INVOKABLE bool remove(const QString &key); | ||
| 46 | Q_INVOKABLE QVariantMap move(const QString &key, qint64 bookId); | ||
| 47 | Q_INVOKABLE bool undo(); | ||
| 48 | Q_INVOKABLE bool resolveConflict(const QString &key, const QString &choice); | ||
| 49 | Q_INVOKABLE void retryNow(); | ||
| 50 | |||
| 51 | // Books for pickers: {bookId, name, account, readOnly, local, showInAll, | ||
| 52 | // useForCompletion, error, lastSync}. | ||
| 53 | Q_INVOKABLE QVariantList books(bool writableOnly = false) const; | ||
| 54 | // D-14: viewed book, else the last used one, else the first writable | ||
| 55 | // CardDAV book, else "On this computer". | ||
| 56 | Q_INVOKABLE qint64 defaultBookId(qint64 viewedBookId = 0) const; | ||
| 57 | Q_INVOKABLE bool setBookFlags(qint64 bookId, bool showInAll, bool useForCompletion); | ||
| 58 | |||
| 59 | Q_INVOKABLE bool forgetCollected(); | ||
| 60 | Q_INVOKABLE bool forgetAddress(const QString &address); | ||
| 61 | // Card for an address (collected or from a mail): prefilled, D-14 book. | ||
| 62 | Q_INVOKABLE QVariantMap draftFor(const QString &name, const QString &address) const; | ||
| 63 | // "c" / "Write mail" (D-10): the preferred address of every card as one | ||
| 64 | // To line ("Name <address>, …"); cards without an address are skipped. | ||
| 65 | Q_INVOKABLE QString recipientsFor(const QStringList &keys) const; | ||
| 66 | // Bulk and menu actions on card keys with one undo step (S97.4.4): | ||
| 67 | // "delete", "move" {bookId}, "addGroup"/"removeGroup" {group}; Sprint 103 | ||
| 68 | // S103.3.8: "relate" {otherKey, type, label}, "setMet" {met}. | ||
| 69 | // {ok, done: n, keys: [keys after the action], error}. | ||
| 70 | Q_INVOKABLE QVariantMap apply(const QStringList &keys, const QString &action, const QVariantMap &fields = {}); | ||
| 71 | // S97.5.5 groups (D-7): rename or delete a group of a book as one undo | ||
| 72 | // step. A CATEGORIES group changes its members' cards; a group card | ||
| 73 | // (KIND:group, Apple group) is renamed or deleted itself. Deleting a group | ||
| 74 | // never deletes its members. | ||
| 75 | Q_INVOKABLE QVariantMap renameGroup(qint64 bookId, const QString &group, const QString &name); | ||
| 76 | Q_INVOKABLE QVariantMap deleteGroup(qint64 bookId, const QString &group); | ||
| 77 | // S97.5.9: other cards that are probably the same person | ||
| 78 | // [{key, displayName, bookName, sameBook}]. | ||
| 79 | Q_INVOKABLE QVariantList possibleDuplicates(const QString &key) const; | ||
| 80 | // Merges `otherKey` into `keepKey` (same book): every address, phone, | ||
| 81 | // postal address, website and group of both, empty fields filled, notes | ||
| 82 | // joined; the other card is deleted. One undo step. {ok, key, error}. | ||
| 83 | Q_INVOKABLE QVariantMap merge(const QString &keepKey, const QString &otherKey); | ||
| 84 | // F100-15: the proposal for merging `keys` (≥ 2, one book, writable): | ||
| 85 | // {ok, error, keep (the most complete card), keys, names [{key, name}], | ||
| 86 | // conflicts [{field, label, options [{text, key}], chosen (key)}], | ||
| 87 | // emails, phones, addresses, groups (counts/names after the merge)}. | ||
| 88 | // With `keepKey`, `chosen` is that card's value (the Keep choice). | ||
| 89 | Q_INVOKABLE QVariantMap mergePlan(const QStringList &keys, const QString &keepKey = QString()) const; | ||
| 90 | // Merges every card of `keys` into `keepKey`; `choices` maps a conflict | ||
| 91 | // field to the key whose value wins. The others are deleted; one undo | ||
| 92 | // step. {ok, key, error}. | ||
| 93 | // `excluded`: value ids of the plan's `sets` the user unchecked (Sprint 107 D-16). | ||
| 94 | Q_INVOKABLE QVariantMap mergeContacts(const QString &keepKey, const QStringList &keys, const QVariantMap &choices, | ||
| 95 | const QStringList &excluded = {}); | ||
| 96 | // "Name <address>, …" of the group's members for Write mail (To or Bcc). | ||
| 97 | Q_INVOKABLE QString groupRecipients(qint64 bookId, const QString &group) const; | ||
| 98 | // Card values (S97.4.1): copy to the clipboard; open only http(s) web | ||
| 99 | // addresses, tel: and geo: (S97.1.9 scheme allowlist), never on hover. | ||
| 100 | Q_INVOKABLE bool copyText(const QString &text) const; | ||
| 101 | Q_INVOKABLE bool openLink(const QString &kind, const QString &value) const; | ||
| 102 | // The editor's date field (S97.3.6): {text} for an ISO date; {ok, iso, | ||
| 103 | // text} for what the user typed ("12.04." → "--04-12"). | ||
| 104 | Q_INVOKABLE QString dateText(const QString &iso) const; | ||
| 105 | Q_INVOKABLE QVariantMap parseDate(const QString &text) const; | ||
| 106 | // Sprint 103 I-6: the current time in an IANA zone ("02:14"); "" for an unknown zone. | ||
| 107 | Q_INVOKABLE QString localTimeText(const QString &zone) const; | ||
| 108 | // Sprint 103 S103.3.1/S103.3.8 (D-5): one RELATED line on the card `key` | ||
| 109 | // saying what `otherKey` is to it ("parent": the other is this person's | ||
| 110 | // parent). `otherKey` is a card key or, for a person without a card, a | ||
| 111 | // name (text form, D-3). `label` names a "custom" type. One undo step. | ||
| 112 | // {ok, key, error}. | ||
| 113 | // A family is one vCard (X-MAILJD-KIND:family) with its members on it | ||
| 114 | // (QuickContactActionsFamilies.cpp). | ||
| 115 | Q_INVOKABLE bool isFamily(const QString &key) const; | ||
| 116 | // Converts older family data once (idempotent, quiet): member-of lines on | ||
| 117 | // people move onto the family's entry, created for a family by name; | ||
| 118 | // entries listing members get the marker. Returns the cards changed. | ||
| 119 | Q_INVOKABLE int migrateFamilies(); | ||
| 120 | Q_INVOKABLE QVariantMap addRelation(const QString &key, const QString &otherKey, const QString &type, | ||
| 121 | const QString &label = {}); | ||
| 122 | // Removes the line `sourceIndex` (RelationIndex row) from the card that | ||
| 123 | // stores it; the inverse row of the other card goes with it. | ||
| 124 | Q_INVOKABLE QVariantMap removeRelation(const QString &storedOnKey, int sourceIndex); | ||
| 125 | // Sprint 103 S103.3.2 editor helpers (interaction.md §3). | ||
| 126 | // The relationship types for the type combobox [{id, label, category, | ||
| 127 | // categoryLabel}], D-4 order; "custom" is the editor's own last entry. | ||
| 128 | // `id` is always the stored type (what the other person is to the | ||
| 129 | // holder). With `holderSide` the labels name the holder's side instead, | ||
| 130 | // as the card reads ("Parent of" for the stored type child), in the order | ||
| 131 | // of those roles — the editor row "Rui · [Parent of ▾] · Ana" can no | ||
| 132 | // longer be read the wrong way round. `holderGender` (the card's gender, | ||
| 133 | // "F"/"M"/…) picks the gendered holder labels ("Mother of", "Daughter of"). | ||
| 134 | Q_INVOKABLE QVariantList relationTypes(bool holderSide = false, const QString &holderGender = {}) const; | ||
| 135 | // The live guard sentence under a relationship row (G2): "Marta Silva is | ||
| 136 | // Ana's sibling"; "" until person and type are set. | ||
| 137 | Q_INVOKABLE QString relationSentence(const QString &targetName, const QString &type, const QString &holderName, | ||
| 138 | const QString &targetGender = {}, const QString &custom = {}) const; | ||
| 139 | // The same relationship with the holder first ("Rui Costa is Ana's | ||
| 140 | // parent" for the stored type child); the target-first sentence for types | ||
| 141 | // without an inverse (custom labels). | ||
| 142 | Q_INVOKABLE QString relationHolderSentence(const QString &holderName, const QString &type, | ||
| 143 | const QString &targetName, const QString &custom = {}) const; | ||
| 144 | // *When* of a meeting: {ok, iso, text} ("Juni 2019" → "2019-06"). | ||
| 145 | Q_INVOKABLE QVariantMap parseLooseDate(const QString &text) const; | ||
| 146 | Q_INVOKABLE QString looseDateText(const QString &iso) const; | ||
| 147 | // Paste recognition (I-10): {recognised, service, kind, label, handle, | ||
| 148 | // value, glyph}; never fetches anything (D-8). | ||
| 149 | Q_INVOKABLE QVariantMap recognizeSocial(const QString &text, const QString &kind) const; | ||
| 150 | // The services for *Change ▾* [{id, label}]. | ||
| 151 | Q_INVOKABLE QVariantList socialServices(const QString &kind) const; | ||
| 152 | // Languages for the chips' completion [{code, name}] (≤ 8) and the name of a code. | ||
| 153 | Q_INVOKABLE QVariantList languageOptions(const QString &fragment) const; | ||
| 154 | Q_INVOKABLE QString languageName(const QString &code) const; | ||
| 155 | // S103.3.3 people picker: cards whose name or address starts a word with | ||
| 156 | // `fragment`, most used first, ≤ 8 [{key, uid, name, address, book, | ||
| 157 | // initials, avatarColor, hasPhoto, gender}]; groups and `exceptKey` left out. | ||
| 158 | // With a me card, "me"/"ich" or the user's name puts it first ({isMe: | ||
| 159 | // true}); without one, "me"/"ich" offers the cards with an account | ||
| 160 | // address ({suggestMe: true}, "Is this you?"). | ||
| 161 | Q_INVOKABLE QVariantList searchPeople(const QString &fragment, const QString &exceptKey = {}) const; | ||
| 162 | // F103-03: the relationship picker's list — the user's own card always | ||
| 163 | // first (without one, the cards with an account address as "Is this | ||
| 164 | // you?"), then the matches of `fragment`, or the most contacted people | ||
| 165 | // when it is empty (the list opens on focus). | ||
| 166 | Q_INVOKABLE QVariantList pickPeople(const QString &fragment, const QString &exceptKey = {}) const; | ||
| 167 | // F103-21: the *Family* picker's list — family entries (cards with members) | ||
| 168 | // and families by name only, each with "N members" as `detail`; the names | ||
| 169 | // containing `fragment` (all when empty), at most 8, by name. A family by | ||
| 170 | // name is {name, textOnly: true}; one named like a family entry is that entry. | ||
| 171 | Q_INVOKABLE QVariantList familyNames(const QString &fragment, const QString &exceptKey = {}) const; | ||
| 172 | // S103.4.5 pin mode (D-10): the GEO parameter of the address at | ||
| 173 | // `addressIndex` (its place in the card's address list), or its removal | ||
| 174 | // ("Use computed position"); one undo step each. {ok, key, error}. | ||
| 175 | Q_INVOKABLE QVariantMap pinAddress(const QString &key, int addressIndex, double latitude, double longitude); | ||
| 176 | Q_INVOKABLE QVariantMap clearPin(const QString &key, int addressIndex); | ||
| 177 | // S103.3.3: *Create contact "Rui Costa"* in the picker — a card with only | ||
| 178 | // the name in the D-14 book, one undo step; returns the picker entry or {}. | ||
| 179 | Q_INVOKABLE QVariantMap createPerson(const QString &name); | ||
| 180 | // S103.3.5 "Met someone…" (interaction.md §5): the prefill {date, dateText, | ||
| 181 | // eventUid, eventTitle, place, people (offered introducers)} from the | ||
| 182 | // event running now or ended in the last 6 hours (or `eventUid`). | ||
| 183 | Q_INVOKABLE QVariantMap metContext(const QString &eventUid = {}) const; | ||
| 184 | // The duplicate guard: the card with this address or exactly this name ({} when none). | ||
| 185 | Q_INVOKABLE QVariantMap existingPerson(const QString &name, const QString &email) const; | ||
| 186 | // {name, email, date, place, eventUid, via, bookId} → a new card with its | ||
| 187 | // meeting (one undo step), or with `existingKey` only the meeting on that | ||
| 188 | // card. {ok, key, error}. | ||
| 189 | Q_INVOKABLE QVariantMap createMet(const QVariantMap &fields); | ||
| 190 | // S103.6.1: the picker entry of the card with this UID, or of the card | ||
| 191 | // that owns this address ({} when none) — event people and attendees. | ||
| 192 | Q_INVOKABLE QVariantMap personForUid(const QString &uid) const; | ||
| 193 | Q_INVOKABLE QVariantMap personForAddress(const QString &address) const; | ||
| 194 | // S103.6.5 (I-5): *Add to contacts* on someone in a mail whose sender is a | ||
| 195 | // contact suggests "met by mail on <day>, through <sender>": the editor's | ||
| 196 | // met map with suggestedBy, or {} (sender unknown, the person is the | ||
| 197 | // sender, no date). | ||
| 198 | Q_INVOKABLE QVariantMap introductionFor(const QString &senderHeader, const QString &address, | ||
| 199 | const QString &dateIso) const; | ||
| 200 | // S103.6.3 (D-15): "this mail is about the person" — link or unlink the | ||
| 201 | // mail (Message-ID, subject, day) on the card; one undo step each. | ||
| 202 | Q_INVOKABLE QVariantMap linkMail(const QString &key, const QString &messageId, const QString &subject, | ||
| 203 | const QString &dateIso); | ||
| 204 | Q_INVOKABLE QVariantMap unlinkMail(const QString &key, const QString &messageId); | ||
| 205 | // The cards that link this mail (the reader's *About:* line) — picker entries. | ||
| 206 | Q_INVOKABLE QVariantList cardsAboutMail(const QString &messageId) const; | ||
| 207 | // S103.6.6: the @-mention at the cursor of the compose body ({start, | ||
| 208 | // fragment}, {} when "@" should stay a plain character — MentionRule). | ||
| 209 | Q_INVOKABLE QVariantMap mentionAt(const QString &text, int cursor) const; | ||
| 210 | // D-6 / S103.1.6: mark a card as the user, or clear the mark. | ||
| 211 | Q_INVOKABLE bool setMe(const QString &key); | ||
| 212 | Q_INVOKABLE void clearMe(); | ||
| 213 | // Cards whose address is one of the accounts' [{key, name, address}]. | ||
| 214 | Q_INVOKABLE QVariantList meSuggestions() const; | ||
| 215 | // S97.5.7: a picture file for the editor → {ok, data (base64 JPEG), error}. | ||
| 216 | Q_INVOKABLE QVariantMap preparePhoto(const QUrl &file) const; | ||
| 217 | // Sprint 103 S103.3.6 (interaction.md §3.8/§3.9): an image from a file | ||
| 218 | // (chosen or dropped) or the clipboard becomes the photo draft — | ||
| 219 | // {ok, preview (base64 JPEG ≤ 1024 px), width, height} or {ok: false, | ||
| 220 | // error} ("This image cannot be used." above 20 MiB or undecodable); | ||
| 221 | // framePhoto() turns the framed square (fractions of the preview) into | ||
| 222 | // the card photo {ok, data (base64 JPEG)}. | ||
| 223 | Q_INVOKABLE QVariantMap loadPhoto(const QUrl &file); | ||
| 224 | Q_INVOKABLE QVariantMap loadPhotoFromClipboard(); | ||
| 225 | Q_INVOKABLE bool clipboardHasImage() const; | ||
| 226 | Q_INVOKABLE QVariantMap framePhoto(qreal x, qreal y, qreal width, qreal height); | ||
| 227 | // The stored vCard as text ("Copy as vCard text", export). | ||
| 228 | Q_INVOKABLE QString vcardText(const QString &key) const; | ||
| 229 | Q_INVOKABLE bool uploadLocalOnly(qint64 bookId); | ||
| 230 | Q_INVOKABLE void keepLocalOnly(); | ||
| 231 | |||
| 232 |
2/2✓ Branch 3 → 4 taken 5 times.
✓ Branch 3 → 5 taken 34 times.
|
39 | QString undoText() const { return m_undo.isEmpty() ? QString() : m_undo.last().text; } |
| 233 | int localOnlyCount() const; | ||
| 234 | qint64 lastUsedBookId() const; | ||
| 235 | bool collectAddresses() const; | ||
| 236 | void setCollectAddresses(bool enabled); | ||
| 237 | QString meKey() const; | ||
| 238 | // The account addresses for meSuggestions() (set by QuickPimBackend). | ||
| 239 | 797 | void setOwnAddresses(std::function<QStringList()> provider) { m_ownAddresses = std::move(provider); } | |
| 240 | // The calendar database for metContext() (set by QuickPimBackend). | ||
| 241 | 797 | void setCalendarPath(const QString &path) { m_calendarPath = path; } | |
| 242 | |||
| 243 | signals: | ||
| 244 | void undoChanged(); | ||
| 245 | void booksChanged(); | ||
| 246 | void settingsChanged(); | ||
| 247 | void meChanged(); | ||
| 248 | // A mail was linked or unlinked (the reader's *About:* line follows). | ||
| 249 | void mailLinksChanged(); | ||
| 250 | // A write finished locally; the toast shows message with Undo when undoable. | ||
| 251 | void done(const QString &message, bool undoable); | ||
| 252 | |||
| 253 | private: | ||
| 254 | QString mergeCards(const QStringList &keys, QList<QVariantMap> *cards) const; | ||
| 255 | // After a merge: cards naming a removed card (relationship, introducer, | ||
| 256 | // group member) name the kept card instead (ContactPeopleMerge::retarget). | ||
| 257 | void retargetReferences(const QSet<QString> &goneUids, const QString &keptKey); | ||
| 258 | struct UndoPart { | ||
| 259 | QString kind; // "delete", "move", "edit", "created" | ||
| 260 | StoredCard card; // delete: the removed card; edit: the card before | ||
| 261 | QString key; // move: the moved card's key now | ||
| 262 | qint64 bookId = 0; // move: the book it came from | ||
| 263 | }; | ||
| 264 | // One user action; a bulk action (S97.4.4) is one step with many parts. | ||
| 265 | struct UndoStep { | ||
| 266 | QString text; | ||
| 267 | QList<UndoPart> parts; | ||
| 268 | }; | ||
| 269 | // Parses the stored card, applies `change` (returns "" or why it refused) | ||
| 270 | // and saves it through the outbox with an "edit" undo step. | ||
| 271 | QVariantMap editPeople(const QString &key, const std::function<QString(ContactCard *)> &change, | ||
| 272 | const QString &message); | ||
| 273 | QVariantMap duplicates(qint64 bookId, const ContactCard &card, const QString &exceptKey) const; | ||
| 274 | // F103-22: a relationship saved on the other card, changed or removed in this card's editor. | ||
| 275 | struct MirrorEdit { | ||
| 276 | QString storedOnKey; | ||
| 277 | int sourceIndex = -1; | ||
| 278 | QString otherKey; // the person chosen now ("" when removed) | ||
| 279 | QString type; // the type seen from the edited card ("" when removed) | ||
| 280 | QString label; | ||
| 281 | }; | ||
| 282 | // Takes the mirrored rows out of `fields`: unchanged ones stay on the other | ||
| 283 | // card, changed ones are saved here (or, on the me card, there), removed ones go. | ||
| 284 | QVariantMap splitMirrors(const QString &key, const QVariantMap &fields, QList<MirrorEdit> *edits) const; | ||
| 285 | // The number of other cards that could not be updated (S106-255). | ||
| 286 | int applyMirrorEdits(const QString &key, const QList<MirrorEdit> &edits); | ||
| 287 | // *Belongs to family* entries of an editor that are not yet on a family's | ||
| 288 | // entry: taken out of the person's relations, written as member lines on | ||
| 289 | // the family (found by key or name, created when missing) after the save. | ||
| 290 | struct FamilyJoin { | ||
| 291 | QString familyKey; // a chosen family entry | ||
| 292 | QString name; // else the family's name | ||
| 293 | }; | ||
| 294 | QVariantMap takeFamilyJoins(const QVariantMap &fields, QList<FamilyJoin> *joins) const; | ||
| 295 | QString ensureFamily(const QString &name, qint64 bookId, QString *error); | ||
| 296 | QVariantMap addMember(const QString &familyKey, const QString &personKey); | ||
| 297 | // Returns how many memberships could not be written. | ||
| 298 | int applyFamilyJoins(const QString &personKey, const QList<FamilyJoin> &joins); | ||
| 299 | void pushUndo(const QString &text, const UndoPart &part); | ||
| 300 | bool undoPart(ContactSyncCoordinator *sync, const UndoPart &part); | ||
| 301 | bool changeGroup(const QString &key, const QString &group, bool add); | ||
| 302 | void rememberBook(qint64 bookId); | ||
| 303 | // Single actions report their own result; inside apply() they are quiet. | ||
| 304 | void report(const QString &message, bool undoable); | ||
| 305 | |||
| 306 | QVariantMap personEntry(const QString &key) const; | ||
| 307 | // S106-298: a UID can live in several books (a copied card keeps it): the | ||
| 308 | // copy in `preferredBook` wins, then one in a writable book, then the oldest. | ||
| 309 | QString cardKeyForUid(const QString &uid, qint64 preferredBook = 0) const; | ||
| 310 | QVariantMap holdPhoto(const QByteArray &bytes); | ||
| 311 | CoordinatorProvider m_coordinator; | ||
| 312 | std::function<QStringList()> m_ownAddresses; | ||
| 313 | QString m_calendarPath; | ||
| 314 | QByteArray m_photoDraft; // the image waiting in the framing step | ||
| 315 | QuickContactModel &m_model; | ||
| 316 | QList<UndoStep> m_undo; | ||
| 317 | // Set while apply() collects the parts of one bulk step. | ||
| 318 | QList<UndoPart> *m_collect = nullptr; | ||
| 319 | bool m_migratingFamilies = false; | ||
| 320 | // S106-297: during migrateFamilies() the writable family entries by | ||
| 321 | // case-folded name (book id, key), read once per run instead of one | ||
| 322 | // full scan per join. | ||
| 323 | using FamilyIndex = QHash<QString, QList<QPair<qint64, QString>>>; | ||
| 324 | FamilyIndex *m_familyIndex = nullptr; | ||
| 325 | // People whose joins failed, with the raw card they failed with: not | ||
| 326 | // tried again in this session until the card changes (S106-297). | ||
| 327 | QHash<QString, size_t> m_familyJoinsFailed; | ||
| 328 | }; | ||
| 329 |