Skip to content
Snippets Groups Projects
Select Git revision
  • 7152b51597cd01a8065bd3e1b8f0f6e98a526aa9
  • master default protected
  • beta/202506161038
  • stable/20250613.0
  • nightly/20250613.0
  • beta/202506101658
  • stable/20250610.0
  • nightly/20250610.0
  • beta/202506091027
  • beta/202506061543
  • nightly/20250605.0
  • beta/202506051039
  • beta/202506051002
  • beta/202506041611
  • beta/202506041335
  • beta/202505231812
  • stable/20250523.0
  • nightly/20250523.0
  • nightly/20250515.0
  • nightly/20250510.0
  • nightly/20250509.1
  • nightly/20250509.0
22 results

conversationmodel.h

Blame
  • Andreas Traczyk's avatar
    Andreas Traczyk authored and François-Simon Fauteux-Chapleau committed
    Change-Id: Ibcd88c5a3c73a0e67f94d70bc420845aa7b8c822
    ff7acf99
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    conversationmodel.h 20.54 KiB
    /****************************************************************************
     *    Copyright (C) 2017-2024 Savoir-faire Linux Inc.                       *
     *   Author: Nicolas Jäger <nicolas.jager@savoirfairelinux.com>             *
     *   Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>           *
     *                                                                          *
     *   This library is free software; you can redistribute it and/or          *
     *   modify it under the terms of the GNU Lesser General Public             *
     *   License as published by the Free Software Foundation; either           *
     *   version 2.1 of the License, or (at your option) any later version.     *
     *                                                                          *
     *   This library is distributed in the hope that it will be useful,        *
     *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
     *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      *
     *   Lesser General Public License for more details.                        *
     *                                                                          *
     *   You should have received a copy of the GNU General Public License      *
     *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
     ***************************************************************************/
    #pragma once
    
    #include "typedefs.h"
    
    #include "api/conversation.h"
    #include "api/profile.h"
    #include "api/datatransfer.h"
    #include "containerview.h"
    
    #include <QObject>
    #include <QVector>
    #include <QMap>
    
    #include <memory>
    #include <deque>
    
    namespace lrc {
    
    class CallbacksHandler;
    class ConversationModelPimpl;
    class Database;
    
    namespace api {
    Q_NAMESPACE
    Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
    
    namespace account {
    struct Info;
    }
    namespace interaction {
    struct Info;
    }
    
    class Lrc;
    class BehaviorController;
    class AccountModel;
    
    enum class ConferenceableItem { CALL, CONTACT };
    Q_ENUM_NS(ConferenceableItem)
    
    enum class FilterType { INVALID = -1, JAMI, SIP, REQUEST, COUNT__ };
    Q_ENUM_NS(FilterType)
    
    struct AccountConversation
    {
        QString convId;
        QString accountId;
    };
    
    /*
     * vector of conversationId and accountId.
     * for calls and contacts contain only one element
     * for conferences contains multiple entries
     */
    typedef QVector<QVector<AccountConversation>> ConferenceableValue;
    
    /**
     *  @brief Class that manages conversation informations.
     */
    class LIB_EXPORT ConversationModel : public QObject
    {
        Q_OBJECT
    public:
        using ConversationQueue = std::deque<conversation::Info>;
        using ConversationQueueProxy = ContainerView<ConversationQueue>;
    
        const account::Info& owner;
    
        ConversationModel(const account::Info& owner,
                          Lrc& lrc,
                          Database& db,
                          const CallbacksHandler& callbacksHandler,
                          const api::BehaviorController& behaviorController);
        ~ConversationModel();
    
        void initConversations();
    
        /**
         * Get unfiltered underlying conversation data. This is intended to
         * serve as the underlying data for QAbstractListModel based objects.
         * The corresponding data mutation signals will need to be responded
         * to with appropriate QAbstractListModel signal forwarding.
         * @return raw conversation queue
         */
        const ConversationQueue& getConversations() const;
    
        /**
         * Get conversations which should be shown client side
         * @return conversations filtered with the current filter
         */
        const ConversationQueueProxy& allFilteredConversations() const;
    
        /**
         * Get conversation for a given uid
         * @param uid conversation uid
         * @return reference to conversation info with given uid
         */
        OptRef<conversation::Info> getConversationForUid(const QString& uid) const;
    
        /**
         * Get conversation for a given peer uri
         * @param uri peer uri
         * @return reference to conversation info with given peer uri
         */
        OptRef<conversation::Info> getConversationForPeerUri(const QString& uri) const;
    
        /**
         * Get conversation for a given call id
         * @param callId call id
         * @return reference to conversation info with given call id
         */
        OptRef<conversation::Info> getConversationForCallId(const QString& callId) const;
    
        /**
         * Get conversations that could be added to conference
         * @param  current conversation id
         * @param  search name filter
         * @return filtered conversations
         */
        QMap<ConferenceableItem, ConferenceableValue> getConferenceableConversations(
            const QString& convId, const QString& filter = {}) const;
        /**
         * Get a custom filtered set of conversations
         * @return conversations filtered
         */
        const ConversationQueueProxy& getFilteredConversations(
            const FilterType& filter = FilterType::INVALID,
            bool forceUpdate = false,
            const bool includeBanned = false) const;
        /**
         * Get a custom filtered set of conversations from profile type
         * @return conversations filtered
         */
        const ConversationQueueProxy& getFilteredConversations(
            const profile::Type& profileType = profile::Type::INVALID,
            bool forceUpdate = false,
            const bool includeBanned = false) const;
        /**
         * Get the conversation at row in the filtered conversations
         * @param  row
         * @return a copy of the conversation
         */
        OptRef<conversation::Info> filteredConversation(unsigned row) const;
        /**
         * Get the search results
         * @return a searchResult
         */
        const ConversationQueue& getAllSearchResults() const;
    
        /**
         * Get the conversation at row in the search results
         * @param  row
         * @return a copy of the conversation
         */
        OptRef<conversation::Info> searchResultForRow(unsigned row) const;
    
        /**
         * Update the searchResults
         * @param new status
         */
        void updateSearchStatus(const QString& status) const;
        /**
         * Emit a filterChanged signal to force the client to refresh the filter. For instance
         * this is required when a contact was banned or un-banned.
         */
        void refreshFilter();
        /**
         * Make permanent a temporary contact or a pending request.
         * Ensure that given conversation is stored permanently into the system.
         * @param uid of the conversation to change.
         * @exception std::out_of_range if uid doesn't correspond to an existing conversation
         */
        void makePermanent(const QString& uid);
        /**
         * Remove a conversation and the contact if it's a dialog
         * @param uid of the conversation
         * @param banned if we want to ban the contact.
         */
        void removeConversation(const QString& uid, bool banned = false);
        /**
         * Get the action wanted by the user when they click on the conversation
         * @param uid of the conversation
         */
        void selectConversation(const QString& uid) const;
        /**
         * Call contacts linked to this conversation
         * @param uid of the conversation
         */
        void placeCall(const QString& uid);
        /**
         * Perform an audio call with contacts linked to this conversation
         * @param uid of the conversation
         */
        void placeAudioOnlyCall(const QString& uid);
        void joinCall(const QString& uid,
                      const QString& confId,
                      const QString& uri,
                      const QString& deviceId,
                      bool isAudioOnly);
        /**
         * Send a message to the conversation
         * @param uid of the conversation
         * @param body of the message
         * @param parentId id of parent message. Default is "" - last message in conversation.
         */
        void sendMessage(const QString& uid, const QString& body, const QString& parentId = "");
        /**
         * Edit a message (empty body = delete message)
         * @param convId        The conversation with the message to edit
         * @param newBody       The new body
         * @param messageId     The id of the message (MUST be by the same author & plain/text)
         */
        void editMessage(const QString& convId, const QString& newBody, const QString& messageId);
        /**
         * React to a message with an emoji
         * @param convId        The conversation id
         * @param emoji         The emoji
         * @param messageId     The id of the message
         */
        void reactMessage(const QString& convId, const QString& emoji, const QString& messageId);
        /**
         * Modify the current filter (will change the result of getFilteredConversations)
         * @param filter the new filter
         */
        void setFilter(const QString& filter);
        void setFilterString(const QString& filter);
        /**
         * Modify the current filter (will change the result of getFilteredConversations)
         * @param filter the new filter (example: SIP,  RING,  REQUEST)
         */
        void setFilter(const FilterType& filter = FilterType::INVALID);
        /**
         * Join participants from A to B and vice-versa.
         * @note conversations must be in a call.
         * @param uidA uid of the conversation A
         * @param uidB uid of the conversation B
         */
        void joinConversations(const QString& uidA, const QString& uidB);
        /**
         * Clear the history of a conversation
         * @param uid of the conversation
         */
        void clearHistory(const QString& uid);
        /**
         * Clears the unread text messages of a conversation
         * @param convId, uid of the conversation
         */
        void clearUnreadInteractions(const QString& convId);
        /**
         * clear all history
         */
        void clearAllHistory();
        /**
         * @param convId
         * @param interactionId
         * @param participant uri
         * @return whether the interaction is last displayed for the conversation
         */
        bool isLastDisplayed(const QString& convId,
                             const QString& interactionId,
                             const QString participant);
        /**
         * delete obsolete history from the database
         * @param days, number of days from today. Below this date, interactions will be deleted
         */
        void deleteObsoleteHistory(int date);
    
        void sendFile(const QString& convUid,
                      const QString& path,
                      const QString& filename,
                      const QString& parent);
    
        void acceptTransfer(const QString& convUid, const QString& interactionId);
    
        void cancelTransfer(const QString& convUid, const QString& interactionId);
    
        void getTransferInfo(const QString& conversationId,
                             const QString& interactionId,
                             api::datatransfer::Info& info) const;
        void removeFile(const QString& conversationId,
                        const QString& interactionId,
                        const QString& path);
    
        /**
         * Starts a search of all medias in a conversation
         */
        void getConvMediasInfos(const QString& accountId,
                                const QString& conversationId,
                                const QString& text,
                                bool isMedia);
        /**
         * @param convUid, uid of the conversation
         * @return the number of unread messages for the conversation
         */
        int getNumberOfUnreadMessagesFor(const QString& convUid);
        /**
         * Send a composing status
         * @param convUid       conversation's id
         * @param isComposing   if is composing
         */
        void setIsComposing(const QString& convUid, bool isComposing);
        /**
         * load messages for conversation
         * @param conversationId conversation's id
         * @param size number of messages should be loaded. Default 1
         * @return id for loading request. -1 if not loaded
         */
        int loadConversationMessages(const QString& conversationId, const int size = 1);
        /**
         * accept request for conversation
         * @param conversationId conversation's id
         */
        void acceptConversationRequest(const QString& conversationId);
        /**
         * add member to conversation
         * @param conversationId conversation's id
         * @param memberId members's id
         */
        void addConversationMember(const QString& conversationId, const QString& memberId);
        /**
         * remove member from conversation
         * @param conversationId conversation's id
         * @param memberId members's id
         */
        void removeConversationMember(const QString& conversationId, const QString& memberId);
        /**
         * get conversation's info
         * @param conversationId conversation's id
         * @return conversation info
         */
        MapStringString getConversationInfos(const QString& conversationId);
        /**
         * get conversation's preferences
         * @param conversationId conversation's id
         * @return conversation preferences
         */
        MapStringString getConversationPreferences(const QString& conversationId);
        /**
         * create a new swarm conversation
         * @param participants  conversation's participants
         * @param infos conversation's infos
         * @return new conversation id
         */
        QString createConversation(const VectorString& participants, const MapStringString& infos = {});
        /**
         * update conversation info
         * @param conversationId conversation's id
         * @param infos
         */
        void updateConversationInfos(const QString& conversationId, MapStringString info);
        /**
         * update conversation's preferences
         * @param conversationId conversation's id
         * @param preferences
         */
        void setConversationPreferences(const QString& conversationId, MapStringString preferences);
        /**
         * Remove first error
         * @param conversationId
         */
        void popFrontError(const QString& conversationId);
        /**
         * Ignore an active call
         * @param convId
         * @param id
         * @param uri
         * @param device
         */
        void ignoreActiveCall(const QString& convId,
                              const QString& id,
                              const QString& uri,
                              const QString& device);
    
        /**
         * @return if conversations requests exists.
         */
        bool hasPendingRequests() const;
        /**
         * @return number of conversations requests
         */
        int pendingRequestCount() const;
        /**
         * @return number of conversations requests + unread
         */
        int notificationsCount() const;
        void reloadHistory() const;
        const VectorString peersForConversation(const QString& conversationId);
    
        // Presentation
    
        /**
         * Get conversation title. This means the title to show in the smartlist
         * @param conversationId
         * @return the title to display
         */
        QString title(const QString& conversationId) const;
        /**
         * Get conversation's description.
         * @param conversationId
         * @return the description to display
         */
        QString description(const QString& conversationId) const;
        /**
         * Get conversation's avatar.
         * @param conversationId
         * @return the avatar to display
         */
        QString avatar(const QString& conversationId) const;
    
        /**
         * Get member's role in conversation
         * @param conversationId
         * @param memberUri
         * @return role
         */
        member::Role memberRole(const QString& conversationId, const QString& memberUri) const;
    
    Q_SIGNALS:
    
        /**
         * Emitted when a conversation receives a new interaction
         * @param uid of conversation
         * @param interactionId
         * @param interactionInfo
         */
        void newInteraction(const QString& uid,
                            QString& interactionId,
                            const interaction::Info& interactionInfo) const;
        /**
         * Emitted when an interaction got removed from the conversation
         * @param convUid conversation which owns the interaction
         * @param interactionId
         */
        void interactionRemoved(const QString& convUid, const QString& interactionId) const;
        /**
         * Emitted when user clear the history of a conversation
         * @param uid
         */
        void conversationCleared(const QString& uid) const;
        /**
         * Emitted when conversation's participant has been updated
         * @param uid
         */
        void conversationUpdated(const QString& uid) const;
        /**
         * Emitted when a conversation detects an error
         * @param uid
         */
        void conversationErrorsUpdated(const QString& uid) const;
        /**
         * Emitted when conversation's preferences has been updated
         * @param uid
         */
        void conversationPreferencesUpdated(const QString& uid) const;
        /**
         * Emitted when conversation's profile has been updated
         * @param uid
         */
        void profileUpdated(const QString& uid) const;
        /**
         * Emitted when the conversations list is modified
         */
        void modelChanged() const;
        /**
         * Emitted when filter has changed
         */
        void filterChanged() const;
        /**
         * Emitted when a conversation has been added
         * @param uid
         */
        void newConversation(const QString& uid) const;
        /**
         * Emitted when a conversation has been removed
         * @param uid
         */
        void conversationRemoved(const QString& uid) const;
        /**
         * Emitted after all history were cleared
         * @note the client must connect this signal to know when update the view of the list
         */
        void allHistoryCleared() const;
        /**
         * Emitted at the end of slotContactAdded and at conversationReady for swarm conversation to
         * notify that an existing conversation can be modified
         * @param uid
         */
        void conversationReady(QString uid, QString participantURI) const;
        /**
         * Emitted when a contact in a conversation is composing a message
         * @param uid           conversation's id
         * @param contactUri    contact's uri
         * @param isComposing   if contact is composing a message
         */
        void composingStatusChanged(const QString& uid,
                                    const QString& contactUri,
                                    bool isComposing) const;
    
        /**
         * Emitted when search status changed
         * @param status
         */
        void searchStatusChanged(const QString& status) const;
        /**
         * Emitted when search result has been updated
         */
        void searchResultUpdated() const;
        void searchResultEnded() const;
        /**
         * Emitted when finish loading messages for conversation
         * @param loadingRequestId  loading request id
         * @param conversationId conversation Id
         */
        void conversationMessagesLoaded(uint32_t loadingRequestId, const QString& conversationId) const;
        /**
         * Emitted when new messages available. When messages loaded from loading request or
         * receiving/sending new interactions
         * @param accountId  account id
         * @param conversationId conversation Id
         */
        void newMessagesAvailable(const QString& accountId, const QString& conversationId) const;
    
        /**
         * Emitted whenever conversation's calls changed
         */
        void activeCallsChanged(const QString& accountId, const QString& conversationId) const;
    
        /**
         * Emitted when creation of conversation started, finished with success or finisfed with error
         * @param accountId  account id
         * @param conversationId conversation Id, when conversation creation started conversationId =
         * participantURI
         * @param participantURI participant uri
         * @param status 0 -started, 1 -created with success, -1 -error
         */
        void creatingConversationEvent(const QString& accountId,
                                       const QString& conversationId,
                                       const QString& participantURI,
                                       int status) const;
    
        /**
         * The following signals are intended for QAbtractListModel compatibility
         */
    
        /*!
         * Emitted before conversations are inserted into the underlying queue
         * @param position The starting row of the insertion
         * @param rows The number of items inserted
         */
        void beginInsertRows(int position, int rows = 1) const;
    
        //! Emitted once insertion is complete
        void endInsertRows() const;
    
        /*!
         * Emitted before conversations are removed from the underlying queue
         * @param position The starting row of the removal
         * @param rows The number of items removed
         */
        void beginRemoveRows(int position, int rows = 1) const;
    
        //! Emitted once removal is complete
        void endRemoveRows() const;
    
        /**
         * Emitted once a conversation has been updated
         * @param position
         */
        void dataChanged(int position) const;
    
        /**
         * Emitted once a message search has been done and processed
         * @param accountId
         * @param messageInformation message datas
         */
        void messagesFoundProcessed(const QString& accountId,
                                    const QMap<QString, interaction::Info>& messageInformation) const;
        /**
         * Emitted once a conversation needs somebody to host the call
         * @param callId
         */
        void needsHost(const QString& conversationId) const;
    
    private:
        std::unique_ptr<ConversationModelPimpl> pimpl_;
    };
    } // namespace api
    } // namespace lrc
    Q_DECLARE_METATYPE(lrc::api::ConversationModel*)