- Create a conference

- List conferences
- Call conference (only from conference list)
- Prepare Mozaic layout (not yet link to conference)
This commit is contained in:
Julien Wadel 2021-12-10 23:12:24 +01:00
parent 6482ecec2c
commit e01d5f895d
74 changed files with 5032 additions and 530 deletions

View file

@ -1543,6 +1543,90 @@ Klik her: <a href="%1">%1</a>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NewConference</name>
<message>
<source>cancelButton</source>
<extracomment>&apos;Cancel&apos; : Cancel button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>startButton</source>
<extracomment>&apos;Launch&apos; : Start button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>missingSubject</source>
<extracomment>&apos;You need to fill a subject.&apos; : Tooltip to warn a user on missing field.</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>missingParticipants</source>
<extracomment>&apos;You need at least %1 participant.&apos; : Tooltip to warn a user that there are not enough participants for the chat creation.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
<message>
<source>missingConferenceURI</source>
<extracomment>&apos;You need to set the conference URI in your account settings to create a conference based chat room.&apos; : Tooltip to warn the user that a setting is missong in its configuration.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>newConferenceTitle</source>
<extracomment>&apos;Start a video conference&apos; : Title of a popup about creation of a video conference</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectLabel</source>
<extracomment>&apos;Subject&apos; : Label of a text field about the subject of the chat room</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectPlaceholder</source>
<extracomment>&apos;Give a subject&apos; : Placeholder in a form about setting a subject</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectTooltip</source>
<extracomment>&apos;Current subject of the Chat Room. It cannot be empty&apos;</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>Explanation about the subject of the chat room</extra-Tooltip>
</message>
<message>
<source>askEncryption</source>
<extracomment>&apos;Would you like to encrypt your conference?&apos; : Ask about setting the conference as secured.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionPlaceholder</source>
<extracomment>&apos;Select participants&apos; : Placeholder for a search on participant to add them in selection.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionTooltip</source>
<extracomment>&apos;Search in your contacts or add a custom one to the chat room.&apos;</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>adminStatus</source>
<extracomment>&apos;Admin&apos; : Admin(istrator)</extracomment>
<translation type="unfinished"></translation>
<extra-one>word for admin status</extra-one>
</message>
<message>
<source>removeParticipantSelection</source>
<extracomment>&apos;Remove this participant from the selection&apos; : Explanation about removing participant from a selection</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>This is a tooltip</extra-Tooltip>
</message>
<message>
<source>requiredField</source>
<extracomment>&apos;Required&apos; : Word relative to a star to explain that it is a requirement (Field form)</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Notice</name>
<message>

View file

@ -1543,6 +1543,90 @@ Klicken Sie hier: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<translation>Letzte Kontakte</translation>
</message>
</context>
<context>
<name>NewConference</name>
<message>
<source>cancelButton</source>
<extracomment>&apos;Cancel&apos; : Cancel button</extracomment>
<translation type="unfinished">ABBRECHEN</translation>
</message>
<message>
<source>startButton</source>
<extracomment>&apos;Launch&apos; : Start button</extracomment>
<translation type="unfinished">START</translation>
</message>
<message>
<source>missingSubject</source>
<extracomment>&apos;You need to fill a subject.&apos; : Tooltip to warn a user on missing field.</extracomment>
<translation type="unfinished">Sie müssen ein Thema eintragen.</translation>
</message>
<message numerus="yes">
<source>missingParticipants</source>
<extracomment>&apos;You need at least %1 participant.&apos; : Tooltip to warn a user that there are not enough participants for the chat creation.</extracomment>
<translation type="unfinished">
<numerusform>Sie benötigen mindestens %1 Teilnehmer.</numerusform>
<numerusform>Sie benötigen mindestens %1 Teilnehmer.</numerusform>
</translation>
</message>
<message>
<source>missingConferenceURI</source>
<extracomment>&apos;You need to set the conference URI in your account settings to create a conference based chat room.&apos; : Tooltip to warn the user that a setting is missong in its configuration.</extracomment>
<translation type="unfinished">Sie müssen eine Konferenz-URI in den Kontoeinstellungen festlegen um einen konferenzbasierten Chatraum zu erstellen.</translation>
</message>
<message>
<source>newConferenceTitle</source>
<extracomment>&apos;Start a video conference&apos; : Title of a popup about creation of a video conference</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectLabel</source>
<extracomment>&apos;Subject&apos; : Label of a text field about the subject of the chat room</extracomment>
<translation type="unfinished">Betreff</translation>
</message>
<message>
<source>subjectPlaceholder</source>
<extracomment>&apos;Give a subject&apos; : Placeholder in a form about setting a subject</extracomment>
<translation type="unfinished">Betreff eingeben</translation>
</message>
<message>
<source>subjectTooltip</source>
<extracomment>&apos;Current subject of the Chat Room. It cannot be empty&apos;</extracomment>
<translation type="unfinished">Aktuelles Thema des Chatraums. Darf nicht leer sein.</translation>
<extra-Tooltip>Explanation about the subject of the chat room</extra-Tooltip>
</message>
<message>
<source>askEncryption</source>
<extracomment>&apos;Would you like to encrypt your conference?&apos; : Ask about setting the conference as secured.</extracomment>
<translation type="unfinished">Möchten Sie den Chat verschlüsseln?</translation>
</message>
<message>
<source>participantSelectionPlaceholder</source>
<extracomment>&apos;Select participants&apos; : Placeholder for a search on participant to add them in selection.</extracomment>
<translation type="unfinished">Wähle Teilnehmer</translation>
</message>
<message>
<source>participantSelectionTooltip</source>
<extracomment>&apos;Search in your contacts or add a custom one to the chat room.&apos;</extracomment>
<translation type="unfinished">In Kontakten suchen oder einen eigenen zum Chatraum hinzufügen.</translation>
</message>
<message>
<source>adminStatus</source>
<extracomment>&apos;Admin&apos; : Admin(istrator)</extracomment>
<translation type="unfinished">Administrator</translation>
<extra-one>word for admin status</extra-one>
</message>
<message>
<source>removeParticipantSelection</source>
<extracomment>&apos;Remove this participant from the selection&apos; : Explanation about removing participant from a selection</extracomment>
<translation type="unfinished">Teilnehmer aus Auswahl entfernen</translation>
<extra-Tooltip>This is a tooltip</extra-Tooltip>
</message>
<message>
<source>requiredField</source>
<extracomment>&apos;Required&apos; : Word relative to a star to explain that it is a requirement (Field form)</extracomment>
<translation type="unfinished">Erforderlich</translation>
</message>
</context>
<context>
<name>Notice</name>
<message>

View file

@ -1543,6 +1543,90 @@ Click here: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<translation>Recent contacts</translation>
</message>
</context>
<context>
<name>NewConference</name>
<message>
<source>cancelButton</source>
<extracomment>&apos;Cancel&apos; : Cancel button</extracomment>
<translation type="unfinished">CANCEL</translation>
</message>
<message>
<source>startButton</source>
<extracomment>&apos;Launch&apos; : Start button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>missingSubject</source>
<extracomment>&apos;You need to fill a subject.&apos; : Tooltip to warn a user on missing field.</extracomment>
<translation type="unfinished">You need to fill a subject.</translation>
</message>
<message numerus="yes">
<source>missingParticipants</source>
<extracomment>&apos;You need at least %1 participant.&apos; : Tooltip to warn a user that there are not enough participants for the chat creation.</extracomment>
<translation type="unfinished">
<numerusform>You need at least %1 participant.</numerusform>
<numerusform>You need at least %1 participants.</numerusform>
</translation>
</message>
<message>
<source>missingConferenceURI</source>
<extracomment>&apos;You need to set the conference URI in your account settings to create a conference based chat room.&apos; : Tooltip to warn the user that a setting is missong in its configuration.</extracomment>
<translation type="unfinished">You need to set the conference URI in your account settings to create a conference based chat room.</translation>
</message>
<message>
<source>newConferenceTitle</source>
<extracomment>&apos;Start a video conference&apos; : Title of a popup about creation of a video conference</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectLabel</source>
<extracomment>&apos;Subject&apos; : Label of a text field about the subject of the chat room</extracomment>
<translation type="unfinished">Subject</translation>
</message>
<message>
<source>subjectPlaceholder</source>
<extracomment>&apos;Give a subject&apos; : Placeholder in a form about setting a subject</extracomment>
<translation type="unfinished">Give a subject</translation>
</message>
<message>
<source>subjectTooltip</source>
<extracomment>&apos;Current subject of the Chat Room. It cannot be empty&apos;</extracomment>
<translation type="unfinished">Current subject of the Chat Room. It cannot be empty.</translation>
<extra-Tooltip>Explanation about the subject of the chat room</extra-Tooltip>
</message>
<message>
<source>askEncryption</source>
<extracomment>&apos;Would you like to encrypt your conference?&apos; : Ask about setting the conference as secured.</extracomment>
<translation type="unfinished">Would you like to encrypt your chat?</translation>
</message>
<message>
<source>participantSelectionPlaceholder</source>
<extracomment>&apos;Select participants&apos; : Placeholder for a search on participant to add them in selection.</extracomment>
<translation type="unfinished">Select participants</translation>
</message>
<message>
<source>participantSelectionTooltip</source>
<extracomment>&apos;Search in your contacts or add a custom one to the chat room.&apos;</extracomment>
<translation type="unfinished">Search in your contacts or add a custom one to the chat room.</translation>
</message>
<message>
<source>adminStatus</source>
<extracomment>&apos;Admin&apos; : Admin(istrator)</extracomment>
<translation type="unfinished">Admin</translation>
<extra-one>word for admin status</extra-one>
</message>
<message>
<source>removeParticipantSelection</source>
<extracomment>&apos;Remove this participant from the selection&apos; : Explanation about removing participant from a selection</extracomment>
<translation type="unfinished">Remove this participant from the selection</translation>
<extra-Tooltip>This is a tooltip</extra-Tooltip>
</message>
<message>
<source>requiredField</source>
<extracomment>&apos;Required&apos; : Word relative to a star to explain that it is a requirement (Field form)</extracomment>
<translation type="unfinished">Required</translation>
</message>
</context>
<context>
<name>Notice</name>
<message>

View file

@ -1543,6 +1543,90 @@ Haga clic aquí: &lt;a href=&quot;%1&quot;&gt;%1 &lt;/a&gt;
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NewConference</name>
<message>
<source>cancelButton</source>
<extracomment>&apos;Cancel&apos; : Cancel button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>startButton</source>
<extracomment>&apos;Launch&apos; : Start button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>missingSubject</source>
<extracomment>&apos;You need to fill a subject.&apos; : Tooltip to warn a user on missing field.</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>missingParticipants</source>
<extracomment>&apos;You need at least %1 participant.&apos; : Tooltip to warn a user that there are not enough participants for the chat creation.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
<message>
<source>missingConferenceURI</source>
<extracomment>&apos;You need to set the conference URI in your account settings to create a conference based chat room.&apos; : Tooltip to warn the user that a setting is missong in its configuration.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>newConferenceTitle</source>
<extracomment>&apos;Start a video conference&apos; : Title of a popup about creation of a video conference</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectLabel</source>
<extracomment>&apos;Subject&apos; : Label of a text field about the subject of the chat room</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectPlaceholder</source>
<extracomment>&apos;Give a subject&apos; : Placeholder in a form about setting a subject</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectTooltip</source>
<extracomment>&apos;Current subject of the Chat Room. It cannot be empty&apos;</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>Explanation about the subject of the chat room</extra-Tooltip>
</message>
<message>
<source>askEncryption</source>
<extracomment>&apos;Would you like to encrypt your conference?&apos; : Ask about setting the conference as secured.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionPlaceholder</source>
<extracomment>&apos;Select participants&apos; : Placeholder for a search on participant to add them in selection.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionTooltip</source>
<extracomment>&apos;Search in your contacts or add a custom one to the chat room.&apos;</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>adminStatus</source>
<extracomment>&apos;Admin&apos; : Admin(istrator)</extracomment>
<translation type="unfinished"></translation>
<extra-one>word for admin status</extra-one>
</message>
<message>
<source>removeParticipantSelection</source>
<extracomment>&apos;Remove this participant from the selection&apos; : Explanation about removing participant from a selection</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>This is a tooltip</extra-Tooltip>
</message>
<message>
<source>requiredField</source>
<extracomment>&apos;Required&apos; : Word relative to a star to explain that it is a requirement (Field form)</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Notice</name>
<message>

View file

@ -1543,6 +1543,90 @@ Cliquez ici : &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<translation>Contacts récents</translation>
</message>
</context>
<context>
<name>NewConference</name>
<message>
<source>cancelButton</source>
<extracomment>&apos;Cancel&apos; : Cancel button</extracomment>
<translation type="unfinished">ANNULER</translation>
</message>
<message>
<source>startButton</source>
<extracomment>&apos;Launch&apos; : Start button</extracomment>
<translation type="unfinished">LANCER</translation>
</message>
<message>
<source>missingSubject</source>
<extracomment>&apos;You need to fill a subject.&apos; : Tooltip to warn a user on missing field.</extracomment>
<translation type="unfinished">Vous devez définir un sujet.</translation>
</message>
<message numerus="yes">
<source>missingParticipants</source>
<extracomment>&apos;You need at least %1 participant.&apos; : Tooltip to warn a user that there are not enough participants for the chat creation.</extracomment>
<translation type="unfinished">
<numerusform>Vous devez ajouter au moins %1 participant.</numerusform>
<numerusform>Vous devez ajouter au moins %1 participants.</numerusform>
</translation>
</message>
<message>
<source>missingConferenceURI</source>
<extracomment>&apos;You need to set the conference URI in your account settings to create a conference based chat room.&apos; : Tooltip to warn the user that a setting is missong in its configuration.</extracomment>
<translation type="unfinished">Vous devez définir l&apos;URI de la conférence dans les paramètres de votre compte pour créer une conférence.</translation>
</message>
<message>
<source>newConferenceTitle</source>
<extracomment>&apos;Start a video conference&apos; : Title of a popup about creation of a video conference</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectLabel</source>
<extracomment>&apos;Subject&apos; : Label of a text field about the subject of the chat room</extracomment>
<translation type="unfinished">Sujet</translation>
</message>
<message>
<source>subjectPlaceholder</source>
<extracomment>&apos;Give a subject&apos; : Placeholder in a form about setting a subject</extracomment>
<translation type="unfinished">Définissez un sujet</translation>
</message>
<message>
<source>subjectTooltip</source>
<extracomment>&apos;Current subject of the Chat Room. It cannot be empty&apos;</extracomment>
<translation type="unfinished">Sujet de la conversation. Il ne peut pas être vide.</translation>
<extra-Tooltip>Explanation about the subject of the chat room</extra-Tooltip>
</message>
<message>
<source>askEncryption</source>
<extracomment>&apos;Would you like to encrypt your conference?&apos; : Ask about setting the conference as secured.</extracomment>
<translation type="unfinished">Voulez-vous chiffrer votre conversation ?</translation>
</message>
<message>
<source>participantSelectionPlaceholder</source>
<extracomment>&apos;Select participants&apos; : Placeholder for a search on participant to add them in selection.</extracomment>
<translation type="unfinished">Choisissez les participants</translation>
</message>
<message>
<source>participantSelectionTooltip</source>
<extracomment>&apos;Search in your contacts or add a custom one to the chat room.&apos;</extracomment>
<translation type="unfinished">Chercher dans vos contacts ou ajouter à la main dans la conversation.</translation>
</message>
<message>
<source>adminStatus</source>
<extracomment>&apos;Admin&apos; : Admin(istrator)</extracomment>
<translation type="unfinished">Admin</translation>
<extra-one>word for admin status</extra-one>
</message>
<message>
<source>removeParticipantSelection</source>
<extracomment>&apos;Remove this participant from the selection&apos; : Explanation about removing participant from a selection</extracomment>
<translation type="unfinished">Enlever ce participant de la sélection</translation>
<extra-Tooltip>This is a tooltip</extra-Tooltip>
</message>
<message>
<source>requiredField</source>
<extracomment>&apos;Required&apos; : Word relative to a star to explain that it is a requirement (Field form)</extracomment>
<translation type="unfinished">Obligatoire</translation>
</message>
</context>
<context>
<name>Notice</name>
<message>

View file

@ -1533,6 +1533,89 @@ Kattintson ide: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<translation>Legutóbbi névjegyek</translation>
</message>
</context>
<context>
<name>NewConference</name>
<message>
<source>cancelButton</source>
<extracomment>&apos;Cancel&apos; : Cancel button</extracomment>
<translation type="unfinished">Mégse</translation>
</message>
<message>
<source>startButton</source>
<extracomment>&apos;Launch&apos; : Start button</extracomment>
<translation type="unfinished">Indítás</translation>
</message>
<message>
<source>missingSubject</source>
<extracomment>&apos;You need to fill a subject.&apos; : Tooltip to warn a user on missing field.</extracomment>
<translation type="unfinished">Ki kell töltenie egy témát.</translation>
</message>
<message numerus="yes">
<source>missingParticipants</source>
<extracomment>&apos;You need at least %1 participant.&apos; : Tooltip to warn a user that there are not enough participants for the chat creation.</extracomment>
<translation type="unfinished">
<numerusform>Legalább %1 résztvevő szükséges.</numerusform>
</translation>
</message>
<message>
<source>missingConferenceURI</source>
<extracomment>&apos;You need to set the conference URI in your account settings to create a conference based chat room.&apos; : Tooltip to warn the user that a setting is missong in its configuration.</extracomment>
<translation type="unfinished">Konferenciaalapú csevegőszoba létrehozásához be kell állítania a konferencia URI-címét a fiókbeállításokban.</translation>
</message>
<message>
<source>newConferenceTitle</source>
<extracomment>&apos;Start a video conference&apos; : Title of a popup about creation of a video conference</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectLabel</source>
<extracomment>&apos;Subject&apos; : Label of a text field about the subject of the chat room</extracomment>
<translation type="unfinished">Téma</translation>
</message>
<message>
<source>subjectPlaceholder</source>
<extracomment>&apos;Give a subject&apos; : Placeholder in a form about setting a subject</extracomment>
<translation type="unfinished">Téma hozzáadása</translation>
</message>
<message>
<source>subjectTooltip</source>
<extracomment>&apos;Current subject of the Chat Room. It cannot be empty&apos;</extracomment>
<translation type="unfinished">A csevegőszoba jelenlegi témája. Nem lehet üres.</translation>
<extra-Tooltip>Explanation about the subject of the chat room</extra-Tooltip>
</message>
<message>
<source>askEncryption</source>
<extracomment>&apos;Would you like to encrypt your conference?&apos; : Ask about setting the conference as secured.</extracomment>
<translation type="unfinished">Szeretné titkosítani a csevegését?</translation>
</message>
<message>
<source>participantSelectionPlaceholder</source>
<extracomment>&apos;Select participants&apos; : Placeholder for a search on participant to add them in selection.</extracomment>
<translation type="unfinished">Résztvevők kiválasztása</translation>
</message>
<message>
<source>participantSelectionTooltip</source>
<extracomment>&apos;Search in your contacts or add a custom one to the chat room.&apos;</extracomment>
<translation type="unfinished">Keressen a névjegyek között vagy adjon hozzá egy egyediet a csevegőszobához.</translation>
</message>
<message>
<source>adminStatus</source>
<extracomment>&apos;Admin&apos; : Admin(istrator)</extracomment>
<translation type="unfinished">Felügyelet</translation>
<extra-one>word for admin status</extra-one>
</message>
<message>
<source>removeParticipantSelection</source>
<extracomment>&apos;Remove this participant from the selection&apos; : Explanation about removing participant from a selection</extracomment>
<translation type="unfinished">Távolítsa el ezt a résztvevőt a kiválasztásból</translation>
<extra-Tooltip>This is a tooltip</extra-Tooltip>
</message>
<message>
<source>requiredField</source>
<extracomment>&apos;Required&apos; : Word relative to a star to explain that it is a requirement (Field form)</extracomment>
<translation type="unfinished">Kötelező</translation>
</message>
</context>
<context>
<name>Notice</name>
<message>

View file

@ -1543,6 +1543,90 @@ Clicca: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NewConference</name>
<message>
<source>cancelButton</source>
<extracomment>&apos;Cancel&apos; : Cancel button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>startButton</source>
<extracomment>&apos;Launch&apos; : Start button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>missingSubject</source>
<extracomment>&apos;You need to fill a subject.&apos; : Tooltip to warn a user on missing field.</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>missingParticipants</source>
<extracomment>&apos;You need at least %1 participant.&apos; : Tooltip to warn a user that there are not enough participants for the chat creation.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
<message>
<source>missingConferenceURI</source>
<extracomment>&apos;You need to set the conference URI in your account settings to create a conference based chat room.&apos; : Tooltip to warn the user that a setting is missong in its configuration.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>newConferenceTitle</source>
<extracomment>&apos;Start a video conference&apos; : Title of a popup about creation of a video conference</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectLabel</source>
<extracomment>&apos;Subject&apos; : Label of a text field about the subject of the chat room</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectPlaceholder</source>
<extracomment>&apos;Give a subject&apos; : Placeholder in a form about setting a subject</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectTooltip</source>
<extracomment>&apos;Current subject of the Chat Room. It cannot be empty&apos;</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>Explanation about the subject of the chat room</extra-Tooltip>
</message>
<message>
<source>askEncryption</source>
<extracomment>&apos;Would you like to encrypt your conference?&apos; : Ask about setting the conference as secured.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionPlaceholder</source>
<extracomment>&apos;Select participants&apos; : Placeholder for a search on participant to add them in selection.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionTooltip</source>
<extracomment>&apos;Search in your contacts or add a custom one to the chat room.&apos;</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>adminStatus</source>
<extracomment>&apos;Admin&apos; : Admin(istrator)</extracomment>
<translation type="unfinished"></translation>
<extra-one>word for admin status</extra-one>
</message>
<message>
<source>removeParticipantSelection</source>
<extracomment>&apos;Remove this participant from the selection&apos; : Explanation about removing participant from a selection</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>This is a tooltip</extra-Tooltip>
</message>
<message>
<source>requiredField</source>
<extracomment>&apos;Required&apos; : Word relative to a star to explain that it is a requirement (Field form)</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Notice</name>
<message>

View file

@ -1533,6 +1533,89 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NewConference</name>
<message>
<source>cancelButton</source>
<extracomment>&apos;Cancel&apos; : Cancel button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>startButton</source>
<extracomment>&apos;Launch&apos; : Start button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>missingSubject</source>
<extracomment>&apos;You need to fill a subject.&apos; : Tooltip to warn a user on missing field.</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>missingParticipants</source>
<extracomment>&apos;You need at least %1 participant.&apos; : Tooltip to warn a user that there are not enough participants for the chat creation.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
</translation>
</message>
<message>
<source>missingConferenceURI</source>
<extracomment>&apos;You need to set the conference URI in your account settings to create a conference based chat room.&apos; : Tooltip to warn the user that a setting is missong in its configuration.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>newConferenceTitle</source>
<extracomment>&apos;Start a video conference&apos; : Title of a popup about creation of a video conference</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectLabel</source>
<extracomment>&apos;Subject&apos; : Label of a text field about the subject of the chat room</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectPlaceholder</source>
<extracomment>&apos;Give a subject&apos; : Placeholder in a form about setting a subject</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectTooltip</source>
<extracomment>&apos;Current subject of the Chat Room. It cannot be empty&apos;</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>Explanation about the subject of the chat room</extra-Tooltip>
</message>
<message>
<source>askEncryption</source>
<extracomment>&apos;Would you like to encrypt your conference?&apos; : Ask about setting the conference as secured.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionPlaceholder</source>
<extracomment>&apos;Select participants&apos; : Placeholder for a search on participant to add them in selection.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionTooltip</source>
<extracomment>&apos;Search in your contacts or add a custom one to the chat room.&apos;</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>adminStatus</source>
<extracomment>&apos;Admin&apos; : Admin(istrator)</extracomment>
<translation type="unfinished"></translation>
<extra-one>word for admin status</extra-one>
</message>
<message>
<source>removeParticipantSelection</source>
<extracomment>&apos;Remove this participant from the selection&apos; : Explanation about removing participant from a selection</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>This is a tooltip</extra-Tooltip>
</message>
<message>
<source>requiredField</source>
<extracomment>&apos;Required&apos; : Word relative to a star to explain that it is a requirement (Field form)</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Notice</name>
<message>

View file

@ -1553,6 +1553,91 @@ Spustelėkite čia: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NewConference</name>
<message>
<source>cancelButton</source>
<extracomment>&apos;Cancel&apos; : Cancel button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>startButton</source>
<extracomment>&apos;Launch&apos; : Start button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>missingSubject</source>
<extracomment>&apos;You need to fill a subject.&apos; : Tooltip to warn a user on missing field.</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>missingParticipants</source>
<extracomment>&apos;You need at least %1 participant.&apos; : Tooltip to warn a user that there are not enough participants for the chat creation.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
<message>
<source>missingConferenceURI</source>
<extracomment>&apos;You need to set the conference URI in your account settings to create a conference based chat room.&apos; : Tooltip to warn the user that a setting is missong in its configuration.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>newConferenceTitle</source>
<extracomment>&apos;Start a video conference&apos; : Title of a popup about creation of a video conference</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectLabel</source>
<extracomment>&apos;Subject&apos; : Label of a text field about the subject of the chat room</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectPlaceholder</source>
<extracomment>&apos;Give a subject&apos; : Placeholder in a form about setting a subject</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectTooltip</source>
<extracomment>&apos;Current subject of the Chat Room. It cannot be empty&apos;</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>Explanation about the subject of the chat room</extra-Tooltip>
</message>
<message>
<source>askEncryption</source>
<extracomment>&apos;Would you like to encrypt your conference?&apos; : Ask about setting the conference as secured.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionPlaceholder</source>
<extracomment>&apos;Select participants&apos; : Placeholder for a search on participant to add them in selection.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionTooltip</source>
<extracomment>&apos;Search in your contacts or add a custom one to the chat room.&apos;</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>adminStatus</source>
<extracomment>&apos;Admin&apos; : Admin(istrator)</extracomment>
<translation type="unfinished"></translation>
<extra-one>word for admin status</extra-one>
</message>
<message>
<source>removeParticipantSelection</source>
<extracomment>&apos;Remove this participant from the selection&apos; : Explanation about removing participant from a selection</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>This is a tooltip</extra-Tooltip>
</message>
<message>
<source>requiredField</source>
<extracomment>&apos;Required&apos; : Word relative to a star to explain that it is a requirement (Field form)</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Notice</name>
<message>

View file

@ -1543,6 +1543,90 @@ Clique aqui: &lt;a href=&quot;%1&quot;&gt;%1 &lt;/a&gt;
<translation>Contatos recentes</translation>
</message>
</context>
<context>
<name>NewConference</name>
<message>
<source>cancelButton</source>
<extracomment>&apos;Cancel&apos; : Cancel button</extracomment>
<translation type="unfinished">CANCELAR</translation>
</message>
<message>
<source>startButton</source>
<extracomment>&apos;Launch&apos; : Start button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>missingSubject</source>
<extracomment>&apos;You need to fill a subject.&apos; : Tooltip to warn a user on missing field.</extracomment>
<translation type="unfinished">Você precisa preencher um assunto.</translation>
</message>
<message numerus="yes">
<source>missingParticipants</source>
<extracomment>&apos;You need at least %1 participant.&apos; : Tooltip to warn a user that there are not enough participants for the chat creation.</extracomment>
<translation type="unfinished">
<numerusform>Você precisa de pelo menos %1 participante.</numerusform>
<numerusform>Você precisa de pelo menos %1 participantes.</numerusform>
</translation>
</message>
<message>
<source>missingConferenceURI</source>
<extracomment>&apos;You need to set the conference URI in your account settings to create a conference based chat room.&apos; : Tooltip to warn the user that a setting is missong in its configuration.</extracomment>
<translation type="unfinished">Você precisa definir o URI da conferência nas configurações da sua conta para criar uma sala de bate-papo baseada em conferência.</translation>
</message>
<message>
<source>newConferenceTitle</source>
<extracomment>&apos;Start a video conference&apos; : Title of a popup about creation of a video conference</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectLabel</source>
<extracomment>&apos;Subject&apos; : Label of a text field about the subject of the chat room</extracomment>
<translation type="unfinished">Assunto</translation>
</message>
<message>
<source>subjectPlaceholder</source>
<extracomment>&apos;Give a subject&apos; : Placeholder in a form about setting a subject</extracomment>
<translation type="unfinished"> um assunto</translation>
</message>
<message>
<source>subjectTooltip</source>
<extracomment>&apos;Current subject of the Chat Room. It cannot be empty&apos;</extracomment>
<translation type="unfinished">Assunto atual da sala de bate-papo. Não pode estar vazio.</translation>
<extra-Tooltip>Explanation about the subject of the chat room</extra-Tooltip>
</message>
<message>
<source>askEncryption</source>
<extracomment>&apos;Would you like to encrypt your conference?&apos; : Ask about setting the conference as secured.</extracomment>
<translation type="unfinished">Você gostaria de criptografar seu bate-papo?</translation>
</message>
<message>
<source>participantSelectionPlaceholder</source>
<extracomment>&apos;Select participants&apos; : Placeholder for a search on participant to add them in selection.</extracomment>
<translation type="unfinished">Selecionar os participantes</translation>
</message>
<message>
<source>participantSelectionTooltip</source>
<extracomment>&apos;Search in your contacts or add a custom one to the chat room.&apos;</extracomment>
<translation type="unfinished">Pesquise em seus contatos ou adicione um personalizado à sala de chat.</translation>
</message>
<message>
<source>adminStatus</source>
<extracomment>&apos;Admin&apos; : Admin(istrator)</extracomment>
<translation type="unfinished">Admin</translation>
<extra-one>word for admin status</extra-one>
</message>
<message>
<source>removeParticipantSelection</source>
<extracomment>&apos;Remove this participant from the selection&apos; : Explanation about removing participant from a selection</extracomment>
<translation type="unfinished">Remover este participante da seleção</translation>
<extra-Tooltip>This is a tooltip</extra-Tooltip>
</message>
<message>
<source>requiredField</source>
<extracomment>&apos;Required&apos; : Word relative to a star to explain that it is a requirement (Field form)</extracomment>
<translation type="unfinished">Obrigatório</translation>
</message>
</context>
<context>
<name>Notice</name>
<message>

View file

@ -1553,6 +1553,91 @@
<translation>Недавние контакты</translation>
</message>
</context>
<context>
<name>NewConference</name>
<message>
<source>cancelButton</source>
<extracomment>&apos;Cancel&apos; : Cancel button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>startButton</source>
<extracomment>&apos;Launch&apos; : Start button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>missingSubject</source>
<extracomment>&apos;You need to fill a subject.&apos; : Tooltip to warn a user on missing field.</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>missingParticipants</source>
<extracomment>&apos;You need at least %1 participant.&apos; : Tooltip to warn a user that there are not enough participants for the chat creation.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
<message>
<source>missingConferenceURI</source>
<extracomment>&apos;You need to set the conference URI in your account settings to create a conference based chat room.&apos; : Tooltip to warn the user that a setting is missong in its configuration.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>newConferenceTitle</source>
<extracomment>&apos;Start a video conference&apos; : Title of a popup about creation of a video conference</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectLabel</source>
<extracomment>&apos;Subject&apos; : Label of a text field about the subject of the chat room</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectPlaceholder</source>
<extracomment>&apos;Give a subject&apos; : Placeholder in a form about setting a subject</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectTooltip</source>
<extracomment>&apos;Current subject of the Chat Room. It cannot be empty&apos;</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>Explanation about the subject of the chat room</extra-Tooltip>
</message>
<message>
<source>askEncryption</source>
<extracomment>&apos;Would you like to encrypt your conference?&apos; : Ask about setting the conference as secured.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionPlaceholder</source>
<extracomment>&apos;Select participants&apos; : Placeholder for a search on participant to add them in selection.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionTooltip</source>
<extracomment>&apos;Search in your contacts or add a custom one to the chat room.&apos;</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>adminStatus</source>
<extracomment>&apos;Admin&apos; : Admin(istrator)</extracomment>
<translation type="unfinished"></translation>
<extra-one>word for admin status</extra-one>
</message>
<message>
<source>removeParticipantSelection</source>
<extracomment>&apos;Remove this participant from the selection&apos; : Explanation about removing participant from a selection</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>This is a tooltip</extra-Tooltip>
</message>
<message>
<source>requiredField</source>
<extracomment>&apos;Required&apos; : Word relative to a star to explain that it is a requirement (Field form)</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Notice</name>
<message>

View file

@ -1543,6 +1543,90 @@ Klicka här: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NewConference</name>
<message>
<source>cancelButton</source>
<extracomment>&apos;Cancel&apos; : Cancel button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>startButton</source>
<extracomment>&apos;Launch&apos; : Start button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>missingSubject</source>
<extracomment>&apos;You need to fill a subject.&apos; : Tooltip to warn a user on missing field.</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>missingParticipants</source>
<extracomment>&apos;You need at least %1 participant.&apos; : Tooltip to warn a user that there are not enough participants for the chat creation.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
<message>
<source>missingConferenceURI</source>
<extracomment>&apos;You need to set the conference URI in your account settings to create a conference based chat room.&apos; : Tooltip to warn the user that a setting is missong in its configuration.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>newConferenceTitle</source>
<extracomment>&apos;Start a video conference&apos; : Title of a popup about creation of a video conference</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectLabel</source>
<extracomment>&apos;Subject&apos; : Label of a text field about the subject of the chat room</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectPlaceholder</source>
<extracomment>&apos;Give a subject&apos; : Placeholder in a form about setting a subject</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectTooltip</source>
<extracomment>&apos;Current subject of the Chat Room. It cannot be empty&apos;</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>Explanation about the subject of the chat room</extra-Tooltip>
</message>
<message>
<source>askEncryption</source>
<extracomment>&apos;Would you like to encrypt your conference?&apos; : Ask about setting the conference as secured.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionPlaceholder</source>
<extracomment>&apos;Select participants&apos; : Placeholder for a search on participant to add them in selection.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionTooltip</source>
<extracomment>&apos;Search in your contacts or add a custom one to the chat room.&apos;</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>adminStatus</source>
<extracomment>&apos;Admin&apos; : Admin(istrator)</extracomment>
<translation type="unfinished"></translation>
<extra-one>word for admin status</extra-one>
</message>
<message>
<source>removeParticipantSelection</source>
<extracomment>&apos;Remove this participant from the selection&apos; : Explanation about removing participant from a selection</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>This is a tooltip</extra-Tooltip>
</message>
<message>
<source>requiredField</source>
<extracomment>&apos;Required&apos; : Word relative to a star to explain that it is a requirement (Field form)</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Notice</name>
<message>

View file

@ -1539,6 +1539,89 @@ Buraya tıklayın: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<translation>Son kişiler</translation>
</message>
</context>
<context>
<name>NewConference</name>
<message>
<source>cancelButton</source>
<extracomment>&apos;Cancel&apos; : Cancel button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>startButton</source>
<extracomment>&apos;Launch&apos; : Start button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>missingSubject</source>
<extracomment>&apos;You need to fill a subject.&apos; : Tooltip to warn a user on missing field.</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>missingParticipants</source>
<extracomment>&apos;You need at least %1 participant.&apos; : Tooltip to warn a user that there are not enough participants for the chat creation.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
</translation>
</message>
<message>
<source>missingConferenceURI</source>
<extracomment>&apos;You need to set the conference URI in your account settings to create a conference based chat room.&apos; : Tooltip to warn the user that a setting is missong in its configuration.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>newConferenceTitle</source>
<extracomment>&apos;Start a video conference&apos; : Title of a popup about creation of a video conference</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectLabel</source>
<extracomment>&apos;Subject&apos; : Label of a text field about the subject of the chat room</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectPlaceholder</source>
<extracomment>&apos;Give a subject&apos; : Placeholder in a form about setting a subject</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectTooltip</source>
<extracomment>&apos;Current subject of the Chat Room. It cannot be empty&apos;</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>Explanation about the subject of the chat room</extra-Tooltip>
</message>
<message>
<source>askEncryption</source>
<extracomment>&apos;Would you like to encrypt your conference?&apos; : Ask about setting the conference as secured.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionPlaceholder</source>
<extracomment>&apos;Select participants&apos; : Placeholder for a search on participant to add them in selection.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionTooltip</source>
<extracomment>&apos;Search in your contacts or add a custom one to the chat room.&apos;</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>adminStatus</source>
<extracomment>&apos;Admin&apos; : Admin(istrator)</extracomment>
<translation type="unfinished"></translation>
<extra-one>word for admin status</extra-one>
</message>
<message>
<source>removeParticipantSelection</source>
<extracomment>&apos;Remove this participant from the selection&apos; : Explanation about removing participant from a selection</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>This is a tooltip</extra-Tooltip>
</message>
<message>
<source>requiredField</source>
<extracomment>&apos;Required&apos; : Word relative to a star to explain that it is a requirement (Field form)</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Notice</name>
<message>

View file

@ -1553,6 +1553,91 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NewConference</name>
<message>
<source>cancelButton</source>
<extracomment>&apos;Cancel&apos; : Cancel button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>startButton</source>
<extracomment>&apos;Launch&apos; : Start button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>missingSubject</source>
<extracomment>&apos;You need to fill a subject.&apos; : Tooltip to warn a user on missing field.</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>missingParticipants</source>
<extracomment>&apos;You need at least %1 participant.&apos; : Tooltip to warn a user that there are not enough participants for the chat creation.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
<message>
<source>missingConferenceURI</source>
<extracomment>&apos;You need to set the conference URI in your account settings to create a conference based chat room.&apos; : Tooltip to warn the user that a setting is missong in its configuration.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>newConferenceTitle</source>
<extracomment>&apos;Start a video conference&apos; : Title of a popup about creation of a video conference</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectLabel</source>
<extracomment>&apos;Subject&apos; : Label of a text field about the subject of the chat room</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectPlaceholder</source>
<extracomment>&apos;Give a subject&apos; : Placeholder in a form about setting a subject</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectTooltip</source>
<extracomment>&apos;Current subject of the Chat Room. It cannot be empty&apos;</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>Explanation about the subject of the chat room</extra-Tooltip>
</message>
<message>
<source>askEncryption</source>
<extracomment>&apos;Would you like to encrypt your conference?&apos; : Ask about setting the conference as secured.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionPlaceholder</source>
<extracomment>&apos;Select participants&apos; : Placeholder for a search on participant to add them in selection.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionTooltip</source>
<extracomment>&apos;Search in your contacts or add a custom one to the chat room.&apos;</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>adminStatus</source>
<extracomment>&apos;Admin&apos; : Admin(istrator)</extracomment>
<translation type="unfinished"></translation>
<extra-one>word for admin status</extra-one>
</message>
<message>
<source>removeParticipantSelection</source>
<extracomment>&apos;Remove this participant from the selection&apos; : Explanation about removing participant from a selection</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>This is a tooltip</extra-Tooltip>
</message>
<message>
<source>requiredField</source>
<extracomment>&apos;Required&apos; : Word relative to a star to explain that it is a requirement (Field form)</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Notice</name>
<message>

View file

@ -1533,6 +1533,89 @@
<translation></translation>
</message>
</context>
<context>
<name>NewConference</name>
<message>
<source>askEncryption</source>
<extracomment>&apos;Would you like to encrypt your conference?&apos; : Ask about setting the conference as secured.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>cancelButton</source>
<extracomment>&apos;Cancel&apos; : Cancel button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>startButton</source>
<extracomment>&apos;Launch&apos; : Start button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>missingSubject</source>
<extracomment>&apos;You need to fill a subject.&apos; : Tooltip to warn a user on missing field.</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>missingParticipants</source>
<extracomment>&apos;You need at least %1 participant.&apos; : Tooltip to warn a user that there are not enough participants for the chat creation.</extracomment>
<translation type="unfinished">
<numerusform>%1</numerusform>
</translation>
</message>
<message>
<source>missingConferenceURI</source>
<extracomment>&apos;You need to set the conference URI in your account settings to create a conference based chat room.&apos; : Tooltip to warn the user that a setting is missong in its configuration.</extracomment>
<translation type="unfinished"> URI </translation>
</message>
<message>
<source>newConferenceTitle</source>
<extracomment>&apos;Start a video conference&apos; : Title of a popup about creation of a video conference</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectLabel</source>
<extracomment>&apos;Subject&apos; : Label of a text field about the subject of the chat room</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectPlaceholder</source>
<extracomment>&apos;Give a subject&apos; : Placeholder in a form about setting a subject</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>subjectTooltip</source>
<extracomment>&apos;Current subject of the Chat Room. It cannot be empty&apos;</extracomment>
<translation type="unfinished"> </translation>
<extra-Tooltip>Explanation about the subject of the chat room</extra-Tooltip>
</message>
<message>
<source>participantSelectionPlaceholder</source>
<extracomment>&apos;Select participants&apos; : Placeholder for a search on participant to add them in selection.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>participantSelectionTooltip</source>
<extracomment>&apos;Search in your contacts or add a custom one to the chat room.&apos;</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>adminStatus</source>
<extracomment>&apos;Admin&apos; : Admin(istrator)</extracomment>
<translation type="unfinished"></translation>
<extra-one>word for admin status</extra-one>
</message>
<message>
<source>removeParticipantSelection</source>
<extracomment>&apos;Remove this participant from the selection&apos; : Explanation about removing participant from a selection</extracomment>
<translation type="unfinished"></translation>
<extra-Tooltip>This is a tooltip</extra-Tooltip>
</message>
<message>
<source>requiredField</source>
<extracomment>&apos;Required&apos; : Word relative to a star to explain that it is a requirement (Field form)</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Notice</name>
<message>

View file

@ -20,6 +20,7 @@
<file>assets/images/call_custom.svg</file>
<file>assets/images/call_history_custom.svg</file>
<file>assets/images/call_quality_custom.svg</file>
<file>assets/images/call_menu_custom.svg</file>
<file>assets/images/call_sign_connected.svg</file>
<file>assets/images/call_sign_ended.svg</file>
<file>assets/images/call_sign_incoming.svg</file>
@ -49,6 +50,7 @@
<file>assets/images/chat_room_custom.svg</file>
<file>assets/images/close_custom.svg</file>
<file>assets/images/collapsed_custom.svg</file>
<file>assets/images/conference_custom.svg</file>
<file>assets/images/contact_add_custom.svg</file>
<file>assets/images/contact_card_photo_custom.svg</file>
<file>assets/images/contact_custom.svg</file>
@ -60,6 +62,7 @@
<file>assets/images/current_account_status_offline.svg</file>
<file>assets/images/current_account_status_dnd.svg</file>
<file>assets/images/current_account_status_busy.svg</file>
<file>assets/images/dialpad_custom.svg</file>
<file>assets/images/declined_incoming_call_custom.svg</file>
<file>assets/images/declined_outgoing_call_custom.svg</file>
<file>assets/images/delete_custom.svg</file>
@ -103,7 +106,6 @@
<file>assets/images/move_to_bottom_custom.svg</file>
<file>assets/images/new_call_custom.svg</file>
<file>assets/images/new_chat_group_custom.svg</file>
<file>assets/images/new_conference_custom.svg</file>
<file>assets/images/options_custom.svg</file>
<file>assets/images/outgoing_call_custom.svg</file>
<file>assets/images/panel_arrow_custom.svg</file>
@ -113,13 +115,16 @@
<file>assets/images/panel_shown_normal.svg</file>
<file>assets/images/panel_shown_hovered.svg</file>
<file>assets/images/panel_shown_pressed.svg</file>
<file>assets/images/participants_custom.svg</file>
<file>assets/images/pause_custom.svg</file>
<file>assets/images/play_custom.svg</file>
<file>assets/images/recording_sign.svg</file>
<file>assets/images/record_custom.svg</file>
<file>assets/images/remove_participant_custom.svg</file>
<file>assets/images/screen_sharing_custom.svg</file>
<file>assets/images/screenshot_custom.svg</file>
<file>assets/images/search_custom.svg</file>
<file>assets/images/schedule_custom.svg</file>
<file>assets/images/secure_level_unsafe.svg</file>
<file>assets/images/secure_level_1.svg</file>
<file>assets/images/secure_level_2.svg</file>
@ -178,6 +183,7 @@
<file>ui/modules/Common/Form/ListForm.qml</file>
<file>ui/modules/Common/Form/ListItemSelector.js</file>
<file>ui/modules/Common/Form/ListItemSelector.qml</file>
<file>ui/modules/Common/Form/Mosaic.qml</file>
<file>ui/modules/Common/Form/MouseArea.qml</file>
<file>ui/modules/Common/Form/Placements/FormEmptyLine.qml</file>
<file>ui/modules/Common/Form/Placements/FormGroup.qml</file>
@ -212,6 +218,8 @@
<file>ui/modules/Common/Misc/Borders.qml</file>
<file>ui/modules/Common/Misc/ForceScrollBar.qml</file>
<file>ui/modules/Common/Misc/Paned.qml</file>
<file>ui/modules/Common/Picker/DatePicker.qml</file>
<file>ui/modules/Common/Picker/TimePicker.qml</file>
<file>ui/modules/Common/Popup/DesktopPopup.qml</file>
<file>ui/modules/Common/Popup/Popup.qml</file>
<file>ui/modules/Common/Popup/PopupShadow.qml</file>
@ -254,6 +262,8 @@
<file>ui/modules/Common/Styles/Menus/MenuStyle.qml</file>
<file>ui/modules/Common/Styles/Misc/ForceScrollBarStyle.qml</file>
<file>ui/modules/Common/Styles/Misc/PanedStyle.qml</file>
<file>ui/modules/Common/Styles/Picker/DatePickerStyle.qml</file>
<file>ui/modules/Common/Styles/Picker/TimePickerStyle.qml</file>
<file>ui/modules/Common/Styles/Popup/PopupStyle.qml</file>
<file>ui/modules/Common/Styles/qmldir</file>
<file>ui/modules/Common/Styles/Tooltip/TooltipStyle.qml</file>
@ -371,6 +381,7 @@
<file>ui/views/App/Calls/CallsWindow.js</file>
<file>ui/views/App/Calls/CallsWindow.qml</file>
<file>ui/views/App/Calls/Conference.qml</file>
<file>ui/views/App/Calls/VideoConference.qml</file>
<file>ui/views/App/Calls/Dialogs/CallSipAddress.qml</file>
<file>ui/views/App/Calls/Dialogs/CallTransfer.qml</file>
<file>ui/views/App/Calls/Dialogs/ConferenceManager.qml</file>
@ -396,6 +407,7 @@
<file>ui/views/App/Main/Assistant/UseAppSipAccountWithPhoneNumber.qml</file>
<file>ui/views/App/Main/Assistant/UseAppSipAccountWithUsername.qml</file>
<file>ui/views/App/Main/Assistant/UseOtherSipAccount.qml</file>
<file>ui/views/App/Main/Conferences.qml</file>
<file>ui/views/App/Main/ContactEdit.js</file>
<file>ui/views/App/Main/ContactEdit.qml</file>
<file>ui/views/App/Main/Contacts.qml</file>
@ -410,6 +422,7 @@
<file>ui/views/App/Main/Dialogs/ManageAccount.js</file>
<file>ui/views/App/Main/Dialogs/ManageAccounts.qml</file>
<file>ui/views/App/Main/Dialogs/NewChatRoom.qml</file>
<file>ui/views/App/Main/Dialogs/NewConference.qml</file>
<file>ui/views/App/Main/Dialogs/ParticipantsDevices.qml</file>
<file>ui/views/App/Main/Home.qml</file>
<file>ui/views/App/Main/HistoryView.qml</file>
@ -441,6 +454,7 @@
<file>ui/views/App/Styles/Calls/CallFullscreenStyle.qml</file>
<file>ui/views/App/Styles/Calls/CallsWindowStyle.qml</file>
<file>ui/views/App/Styles/Calls/ConferenceStyle.qml</file>
<file>ui/views/App/Styles/Calls/VideoConferenceStyle.qml</file>
<file>ui/views/App/Styles/Calls/Dialogs/CallSipAddressStyle.qml</file>
<file>ui/views/App/Styles/Calls/Dialogs/CallTransferStyle.qml</file>
<file>ui/views/App/Styles/Calls/Dialogs/ConferenceManagerStyle.qml</file>
@ -452,6 +466,7 @@
<file>ui/views/App/Styles/Main/Assistant/CreateAppSipAccountStyle.qml</file>
<file>ui/views/App/Styles/Main/AssistantStyle.qml</file>
<file>ui/views/App/Styles/Main/Assistant/UseAppSipAccountStyle.qml</file>
<file>ui/views/App/Styles/Main/ConferencesStyle.qml</file>
<file>ui/views/App/Styles/Main/ContactEditStyle.qml</file>
<file>ui/views/App/Styles/Main/ContactsStyle.qml</file>
<file>ui/views/App/Styles/Main/ConversationStyle.qml</file>
@ -461,6 +476,7 @@
<file>ui/views/App/Styles/Main/Dialogs/InfoChatRoomStyle.qml</file>
<file>ui/views/App/Styles/Main/Dialogs/InfoEncryptionStyle.qml</file>
<file>ui/views/App/Styles/Main/Dialogs/NewChatRoomStyle.qml</file>
<file>ui/views/App/Styles/Main/Dialogs/NewConferenceStyle.qml</file>
<file>ui/views/App/Styles/Main/Dialogs/ManageAccountsStyle.qml</file>
<file>ui/views/App/Styles/Main/Dialogs/ParticipantsDevicesStyle.qml</file>
<file>ui/views/App/Styles/Main/HomeStyle.qml</file>

View file

@ -343,6 +343,9 @@ void App::initContentApp () {
// Change colors if necessary.
mColorListModel->useConfig(config);
mImageListModel->useConfig(config);
// There is no more database for callback. Setting it in the configuration before starting the core will do migration.
// When the migration is done by SDK, further migrations on call logs will do nothing. It is safe to use .
config->setString("storage", "call_logs_db_uri", Paths::getCallHistoryFilePath());
// Init core.
CoreManager::init(this, Utils::coreStringToAppString(configPath));
@ -611,6 +614,7 @@ void App::registerTypes () {
qRegisterMetaType<std::shared_ptr<ChatMessageModel>>();
qRegisterMetaType<std::shared_ptr<ChatNoticeModel>>();
qRegisterMetaType<std::shared_ptr<ChatCallModel>>();
qRegisterMetaType<std::shared_ptr<ConferenceInfoModel>>();
//qRegisterMetaType<std::shared_ptr<ChatEvent>>();
LinphoneEnums::registerMetaTypes();
@ -621,7 +625,9 @@ void App::registerTypes () {
registerType<CameraPreview>("CameraPreview");
registerType<ChatRoomProxyModel>("ChatRoomProxyModel");
registerType<ConferenceHelperModel>("ConferenceHelperModel");
registerType<ConferenceModel>("ConferenceModel");
registerType<ConferenceProxyModel>("ConferenceProxyModel");
registerType<ConferenceInfoModel>("ConferenceInfoModel");
registerType<ConferenceInfoProxyModel>("ConferenceInfoProxyModel");
registerType<ContactsListProxyModel>("ContactsListProxyModel");
registerType<ContactsImporterListProxyModel>("ContactsImporterListProxyModel");
registerType<ContentProxyModel>("ContentProxyModel");
@ -659,6 +665,8 @@ void App::registerTypes () {
registerUncreatableType<ColorModel>("ColorModel");
registerUncreatableType<ImageModel>("ImageModel");
registerUncreatableType<ConferenceHelperModel::ConferenceAddModel>("ConferenceAddModel");
registerUncreatableType<ConferenceModel>("ConferenceModel");
registerUncreatableType<ConferenceInfoListModel>("ConferenceInfoListModel");
registerUncreatableType<ContactModel>("ContactModel");
registerUncreatableType<ContactsImporterModel>("ContactsImporterModel");
registerUncreatableType<ContentModel>("ContentModel");

View file

@ -36,6 +36,10 @@
#include "codecs/VideoCodecsModel.hpp"
#include "conference/ConferenceAddModel.hpp"
#include "conference/ConferenceModel.hpp"
#include "conference/ConferenceProxyModel.hpp"
#include "conferenceInfo/ConferenceInfoModel.hpp"
#include "conferenceInfo/ConferenceInfoListModel.hpp"
#include "conferenceInfo/ConferenceInfoProxyModel.hpp"
#include "contact/ContactModel.hpp"
#include "contact/VcardModel.hpp"
#include "contacts/ContactsListModel.hpp"

View file

@ -27,6 +27,7 @@
#include "app/App.hpp"
#include "components/calls/CallsListModel.hpp"
#include "components/chat-room/ChatRoomModel.hpp"
#include "components/conference/ConferenceModel.hpp"
#include "components/contact/ContactModel.hpp"
#include "components/contacts/ContactsListModel.hpp"
#include "components/core/CoreHandlers.hpp"
@ -49,9 +50,10 @@ constexpr char AutoAnswerObjectName[] = "auto-answer-timer";
}
CallModel::CallModel (shared_ptr<linphone::Call> call){
Q_CHECK_PTR(call);
mCall = call;
mCall->setData("call-model", *this);
if(mCall)
mCall->setData("call-model", *this);
updateIsInConference();
@ -82,13 +84,18 @@ CallModel::CallModel (shared_ptr<linphone::Call> call){
QObject::connect(mSearch.get(), SIGNAL(searchReceived(std::list<std::shared_ptr<linphone::SearchResult>> )), this, SLOT(searchReceived(std::list<std::shared_ptr<linphone::SearchResult>>)));
mMagicSearch->addListener(mSearch);
mRemoteAddress = mCall->getRemoteAddress()->clone();
if(mCall) {
mRemoteAddress = mCall->getRemoteAddress()->clone();
if(mCall->getConference())
mConferenceModel = std::make_shared<ConferenceModel>(mCall->getConference());
}
mMagicSearch->getContactListFromFilterAsync(mRemoteAddress->getUsername(),mRemoteAddress->getDomain());
}
CallModel::~CallModel () {
mMagicSearch->removeListener(mSearch);
mCall->unsetData("call-model");
if(mCall)
mCall->unsetData("call-model");
}
// -----------------------------------------------------------------------------
@ -98,7 +105,7 @@ QString CallModel::getPeerAddress () const {
}
QString CallModel::getLocalAddress () const {
return Utils::coreStringToAppString(mCall->getCallLog()->getLocalAddress()->asStringUriOnly());
return mCall ? Utils::coreStringToAppString(mCall->getCallLog()->getLocalAddress()->asStringUriOnly()) : "";
}
QString CallModel::getFullPeerAddress () const {
@ -106,17 +113,17 @@ QString CallModel::getFullPeerAddress () const {
}
QString CallModel::getFullLocalAddress () const {
return Utils::coreStringToAppString(mCall->getCallLog()->getLocalAddress()->asString());
return mCall ? Utils::coreStringToAppString(mCall->getCallLog()->getLocalAddress()->asString()) : "";
}
// -----------------------------------------------------------------------------
ContactModel *CallModel::getContactModel() const{
QString cleanedAddress = Utils::cleanSipAddress(Utils::coreStringToAppString(mCall->getRemoteAddress()->asString()));
QString cleanedAddress = mCall ? Utils::cleanSipAddress(Utils::coreStringToAppString(mCall->getRemoteAddress()->asString())) : "";
return CoreManager::getInstance()->getContactsListModel()->findContactModelFromSipAddress(cleanedAddress);
}
ChatRoomModel * CallModel::getChatRoomModel() const{
if(mCall->getCallLog()->getCallId() != "") {
if(mCall && mCall->getCallLog()->getCallId() != "") {
auto currentParams = mCall->getCurrentParams();
bool isEncrypted = currentParams->getMediaEncryption() != linphone::MediaEncryption::None;
SettingsModel * settingsModel = CoreManager::getInstance()->getSettingsModel();
@ -154,6 +161,14 @@ ChatRoomModel * CallModel::getChatRoomModel() const{
return nullptr;
}
std::shared_ptr<ConferenceModel> CallModel::getConferenceModel() const{
return mConferenceModel;
}
bool CallModel::isConference () const{
return mCall->getConference() != nullptr;
}
// -----------------------------------------------------------------------------
void CallModel::setRecordFile (const shared_ptr<linphone::CallParams> &callParams) {
callParams->setRecordFile(Utils::appStringToCoreString(
@ -199,7 +214,7 @@ void CallModel::updateStats (const shared_ptr<const linphone::CallStats> &callSt
// -----------------------------------------------------------------------------
float CallModel::getSpeakerVolumeGain () const {
float gain = mCall->getSpeakerVolumeGain();
float gain = mCall ? mCall->getSpeakerVolumeGain() : 0;
if( gain < 0)
gain = CoreManager::getInstance()->getSettingsModel()->getPlaybackGain();
return gain;
@ -207,7 +222,7 @@ float CallModel::getSpeakerVolumeGain () const {
void CallModel::setSpeakerVolumeGain (float volume) {
Q_ASSERT(volume >= 0.0f && volume <= 1.0f);
if( mCall->getSpeakerVolumeGain() >= 0)
if( mCall && mCall->getSpeakerVolumeGain() >= 0)
mCall->setSpeakerVolumeGain(volume);
else
CoreManager::getInstance()->getSettingsModel()->setPlaybackGain(volume);
@ -215,7 +230,7 @@ void CallModel::setSpeakerVolumeGain (float volume) {
}
float CallModel::getMicroVolumeGain () const {
float gain = mCall->getMicrophoneVolumeGain();
float gain = mCall ? mCall->getMicrophoneVolumeGain() : 0.0;
if( gain < 0)
gain = CoreManager::getInstance()->getSettingsModel()->getCaptureGain();
return gain;
@ -223,7 +238,7 @@ float CallModel::getMicroVolumeGain () const {
void CallModel::setMicroVolumeGain (float volume) {
Q_ASSERT(volume >= 0.0f && volume <= 1.0f);
if(mCall->getMicrophoneVolumeGain() >= 0)
if(mCall && mCall->getMicrophoneVolumeGain() >= 0)
mCall->setMicrophoneVolumeGain(volume);
else
CoreManager::getInstance()->getSettingsModel()->setCaptureGain(volume);
@ -252,7 +267,8 @@ void CallModel::acceptWithVideo () {
void CallModel::terminate () {
CoreManager *core = CoreManager::getInstance();
core->lockVideoRender();
mCall->terminate();
if(mCall)
mCall->terminate();
core->unlockVideoRender();
}
@ -267,7 +283,7 @@ void CallModel::askForAttendedTransfer () {
}
bool CallModel::transferTo (const QString &sipAddress) {
bool failure = !!mCall->transferTo(Utils::interpretUrl(sipAddress));
bool failure = mCall ? !!mCall->transferTo(Utils::interpretUrl(sipAddress)) : false;
if (failure)
qWarning() << QStringLiteral("Unable to transfer: `%1`.").arg(sipAddress);
return !failure;
@ -280,7 +296,7 @@ bool CallModel::transferToAnother (const QString &peerAddress) {
qWarning() << QStringLiteral("Unable to transfer to another: `%1` (peer not found)").arg(peerAddress);
return false;
}
bool failure = !!transferCallModel->mCall->transferToAnother(mCall);
bool failure = mCall ? !!transferCallModel->mCall->transferToAnother(mCall) : false;
if (failure)
qWarning() << QStringLiteral("Unable to transfer to another: `%1` (transfer failed)").arg(peerAddress);
return !failure;
@ -288,17 +304,20 @@ bool CallModel::transferToAnother (const QString &peerAddress) {
// -----------------------------------------------------------------------------
void CallModel::acceptVideoRequest () {
shared_ptr<linphone::CallParams> params = CoreManager::getInstance()->getCore()->createCallParams(mCall);
params->enableVideo(true);
mCall->acceptUpdate(params);
if(mCall) {
shared_ptr<linphone::CallParams> params = CoreManager::getInstance()->getCore()->createCallParams(mCall);
params->enableVideo(true);
mCall->acceptUpdate(params);
}
}
void CallModel::rejectVideoRequest () {
shared_ptr<linphone::CallParams> params = CoreManager::getInstance()->getCore()->createCallParams(mCall);
params->enableVideo(false);
if(mCall) {
shared_ptr<linphone::CallParams> params = CoreManager::getInstance()->getCore()->createCallParams(mCall);
params->enableVideo(false);
mCall->acceptUpdate(params);
mCall->acceptUpdate(params);
}
}
void CallModel::takeSnapshot () {
@ -314,7 +333,8 @@ void CallModel::takeSnapshot () {
qInfo() << QStringLiteral("Take snapshot of call:") << this;
const QString filePath(CoreManager::getInstance()->getSettingsModel()->getSavedScreenshotsFolder().append(newName));
mCall->takeVideoSnapshot(Utils::appStringToCoreString(filePath));
if(mCall)
mCall->takeVideoSnapshot(Utils::appStringToCoreString(filePath));
App::getInstance()->getNotifier()->notifySnapshotWasTaken(filePath);
}
@ -323,8 +343,8 @@ void CallModel::startRecording () {
return;
qInfo() << QStringLiteral("Start recording call:") << this;
mCall->startRecording();
if(mCall)
mCall->startRecording();
mRecording = true;
emit recordingChanged(true);
@ -337,12 +357,13 @@ void CallModel::stopRecording () {
qInfo() << QStringLiteral("Stop recording call:") << this;
mRecording = false;
mCall->stopRecording();
if(mCall) {
mCall->stopRecording();
App::getInstance()->getNotifier()->notifyRecordingCompleted(
App::getInstance()->getNotifier()->notifyRecordingCompleted(
Utils::coreStringToAppString(mCall->getParams()->getRecordFile())
);
}
emit recordingChanged(false);
}
@ -397,7 +418,7 @@ void CallModel::handleCallStateChanged (const shared_ptr<linphone::Call> &call,
break;
case linphone::Call::State::UpdatedByRemote:
if (!mCall->getCurrentParams()->videoEnabled() && mCall->getRemoteParams()->videoEnabled()) {
if (mCall && !mCall->getCurrentParams()->videoEnabled() && mCall->getRemoteParams()->videoEnabled()) {
mCall->deferUpdate();
emit videoRequested();
}
@ -436,17 +457,19 @@ void CallModel::accept (bool withVideo) {
}
qApp->processEvents(); // Process GUI events before accepting in order to be synchronized with Call objects and be ready to get SDK events
shared_ptr<linphone::Core> core = coreManager->getCore();
shared_ptr<linphone::CallParams> params = core->createCallParams(mCall);
params->enableVideo(withVideo);
setRecordFile(params);
if(mCall) {
shared_ptr<linphone::CallParams> params = core->createCallParams(mCall);
params->enableVideo(withVideo);
setRecordFile(params);
mCall->acceptWithParams(params);
mCall->acceptWithParams(params);
}
}
// -----------------------------------------------------------------------------
void CallModel::updateIsInConference () {
if (mIsInConference != mCall->getCurrentParams()->getLocalConferenceMode()) {
if (mIsInConference != (mCall && mCall->getCurrentParams()->getLocalConferenceMode() )) {
mIsInConference = !mIsInConference;
}
emit isInConferenceChanged(mIsInConference);
@ -465,40 +488,43 @@ void CallModel::stopAutoAnswerTimer () const {
// -----------------------------------------------------------------------------
CallModel::CallStatus CallModel::getStatus () const {
switch (mCall->getState()) {
case linphone::Call::State::Connected:
case linphone::Call::State::StreamsRunning:
return CallStatusConnected;
case linphone::Call::State::End:
case linphone::Call::State::Error:
case linphone::Call::State::Referred:
case linphone::Call::State::Released:
return CallStatusEnded;
case linphone::Call::State::Paused:
case linphone::Call::State::PausedByRemote:
case linphone::Call::State::Pausing:
case linphone::Call::State::Resuming:
return CallStatusPaused;
case linphone::Call::State::Updating:
case linphone::Call::State::UpdatedByRemote:
return mPausedByRemote ? CallStatusPaused : CallStatusConnected;
case linphone::Call::State::EarlyUpdatedByRemote:
case linphone::Call::State::EarlyUpdating:
case linphone::Call::State::Idle:
case linphone::Call::State::IncomingEarlyMedia:
case linphone::Call::State::IncomingReceived:
case linphone::Call::State::OutgoingEarlyMedia:
case linphone::Call::State::OutgoingInit:
case linphone::Call::State::OutgoingProgress:
case linphone::Call::State::OutgoingRinging:
break;
}
return mCall->getDir() == linphone::Call::Dir::Incoming ? CallStatusIncoming : CallStatusOutgoing;
if(mCall){
switch (mCall->getState()) {
case linphone::Call::State::Connected:
case linphone::Call::State::StreamsRunning:
return CallStatusConnected;
case linphone::Call::State::End:
case linphone::Call::State::Error:
case linphone::Call::State::Referred:
case linphone::Call::State::Released:
return CallStatusEnded;
case linphone::Call::State::Paused:
case linphone::Call::State::PausedByRemote:
case linphone::Call::State::Pausing:
case linphone::Call::State::Resuming:
return CallStatusPaused;
case linphone::Call::State::Updating:
case linphone::Call::State::UpdatedByRemote:
return mPausedByRemote ? CallStatusPaused : CallStatusConnected;
case linphone::Call::State::EarlyUpdatedByRemote:
case linphone::Call::State::EarlyUpdating:
case linphone::Call::State::Idle:
case linphone::Call::State::IncomingEarlyMedia:
case linphone::Call::State::IncomingReceived:
case linphone::Call::State::OutgoingEarlyMedia:
case linphone::Call::State::OutgoingInit:
case linphone::Call::State::OutgoingProgress:
case linphone::Call::State::OutgoingRinging:
break;
}
return mCall->getDir() == linphone::Call::Dir::Incoming ? CallStatusIncoming : CallStatusOutgoing;
}else
return CallStatusIdle;
}
// -----------------------------------------------------------------------------
@ -509,7 +535,7 @@ void CallModel::acceptWithAutoAnswerDelay () {
// Use auto-answer if activated and it's the only call.
if (settingsModel->getAutoAnswerStatus() && coreManager->getCore()->getCallsNb() == 1) {
if (mCall->getRemoteParams()->videoEnabled() && settingsModel->getAutoAnswerVideoStatus() && settingsModel->getVideoSupported())
if (mCall && mCall->getRemoteParams()->videoEnabled() && settingsModel->getAutoAnswerVideoStatus() && settingsModel->getVideoSupported())
acceptWithVideo();
else
accept();
@ -549,23 +575,23 @@ void CallModel::setCallErrorFromReason (linphone::Reason reason) {
// -----------------------------------------------------------------------------
int CallModel::getDuration () const {
return mCall->getDuration();
return mCall ? mCall->getDuration() : 0;
}
float CallModel::getQuality () const {
return mCall->getCurrentQuality();
return mCall ? mCall->getCurrentQuality() : 0.0;
}
// -----------------------------------------------------------------------------
float CallModel::getSpeakerVu () const {
if (mCall->getState() == linphone::Call::State::StreamsRunning)
if (mCall && mCall->getState() == linphone::Call::State::StreamsRunning)
return MediastreamerUtils::computeVu(mCall->getPlayVolume());
return 0.0;
}
float CallModel::getMicroVu () const {
if (mCall->getState() == linphone::Call::State::StreamsRunning)
if (mCall && mCall->getState() == linphone::Call::State::StreamsRunning)
return MediastreamerUtils::computeVu(mCall->getRecordVolume());
return 0.0;
}
@ -573,28 +599,28 @@ float CallModel::getMicroVu () const {
// -----------------------------------------------------------------------------
bool CallModel::getSpeakerMuted () const {
return mCall->getSpeakerMuted();
return mCall && mCall->getSpeakerMuted();
}
void CallModel::setSpeakerMuted (bool status) {
if (status == getSpeakerMuted())
return;
mCall->setSpeakerMuted(status);
if(mCall)
mCall->setSpeakerMuted(status);
emit speakerMutedChanged(getSpeakerMuted());
}
// -----------------------------------------------------------------------------
bool CallModel::getMicroMuted () const {
return mCall->getMicrophoneMuted();
return mCall && mCall->getMicrophoneMuted();
}
void CallModel::setMicroMuted (bool status) {
if (status == getMicroMuted())
return;
mCall->setMicrophoneMuted(status);
if(mCall)
mCall->setMicrophoneMuted(status);
emit microMutedChanged(getMicroMuted());
}
@ -605,23 +631,25 @@ bool CallModel::getPausedByUser () const {
}
void CallModel::setPausedByUser (bool status) {
switch (mCall->getState()) {
case linphone::Call::State::Connected:
case linphone::Call::State::StreamsRunning:
case linphone::Call::State::Paused:
case linphone::Call::State::PausedByRemote:
break;
default: return;
if(mCall){
switch (mCall->getState()) {
case linphone::Call::State::Connected:
case linphone::Call::State::StreamsRunning:
case linphone::Call::State::Paused:
case linphone::Call::State::PausedByRemote:
break;
default: return;
}
if (status) {
if (!mPausedByUser)
mCall->pause();
return;
}
if (mPausedByUser)
mCall->resume();
}
if (status) {
if (!mPausedByUser)
mCall->pause();
return;
}
if (mPausedByUser)
mCall->resume();
}
// -----------------------------------------------------------------------------
@ -631,8 +659,11 @@ bool CallModel::getRemoteVideoEnabled () const {
}
bool CallModel::getVideoEnabled () const {
shared_ptr<const linphone::CallParams> params = mCall->getCurrentParams();
return params && params->videoEnabled() && getStatus() == CallStatusConnected;
if(mCall){
shared_ptr<const linphone::CallParams> params = mCall->getCurrentParams();
return params && params->videoEnabled() && getStatus() == CallStatusConnected;
}else
return true;
}
void CallModel::setVideoEnabled (bool status) {
@ -641,35 +672,38 @@ void CallModel::setVideoEnabled (bool status) {
qWarning() << QStringLiteral("Unable to update video call property. (Video not supported.)");
return;
}
switch (mCall->getState()) {
case linphone::Call::State::Connected:
case linphone::Call::State::StreamsRunning:
break;
default: return;
if(mCall) {
switch (mCall->getState()) {
case linphone::Call::State::Connected:
case linphone::Call::State::StreamsRunning:
break;
default: return;
}
if (status == getVideoEnabled())
return;
shared_ptr<linphone::CallParams> params = core->createCallParams(mCall);
params->enableVideo(status);
mCall->update(params);
}
if (status == getVideoEnabled())
return;
shared_ptr<linphone::CallParams> params = core->createCallParams(mCall);
params->enableVideo(status);
mCall->update(params);
}
// -----------------------------------------------------------------------------
bool CallModel::getUpdating () const {
switch (mCall->getState()) {
case linphone::Call::State::Connected:
case linphone::Call::State::StreamsRunning:
case linphone::Call::State::Paused:
case linphone::Call::State::PausedByRemote:
return false;
default:
break;
if(mCall) {
switch (mCall->getState()) {
case linphone::Call::State::Connected:
case linphone::Call::State::StreamsRunning:
case linphone::Call::State::Paused:
case linphone::Call::State::PausedByRemote:
return false;
default:
break;
}
}
return true;
@ -684,21 +718,24 @@ bool CallModel::getRecording () const {
void CallModel::sendDtmf (const QString &dtmf) {
const char key = dtmf.constData()[0].toLatin1();
qInfo() << QStringLiteral("Send dtmf: `%1`.").arg(key);
mCall->sendDtmf(key);
if(mCall)
mCall->sendDtmf(key);
CoreManager::getInstance()->getCore()->playDtmf(key, DtmfSoundDelay);
}
// -----------------------------------------------------------------------------
void CallModel::verifyAuthenticationToken (bool verify) {
mCall->setAuthenticationTokenVerified(verify);
if(mCall)
mCall->setAuthenticationTokenVerified(verify);
emit securityUpdated();
}
// -----------------------------------------------------------------------------
void CallModel::updateStreams () {
mCall->update(nullptr);
if(mCall)
mCall->update(nullptr);
}
void CallModel::toggleSpeakerMute(){
setSpeakerMuted(!getSpeakerMuted());
@ -727,30 +764,34 @@ void CallModel::searchReceived(std::list<std::shared_ptr<linphone::SearchResult>
}
void CallModel::callEnded(){
ChatRoomModel * model = getChatRoomModel();
if(model){
model->callEnded(mCall);
}else{// No chat rooms have been associated for this call. Search one in current chat room list
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
std::shared_ptr<linphone::ChatRoomParams> params = core->createDefaultChatRoomParams();
std::list<std::shared_ptr<linphone::Address>> participants;
if(mCall){
ChatRoomModel * model = getChatRoomModel();
auto chatRoom = core->searchChatRoom(params, mCall->getCallLog()->getLocalAddress()
, mCall->getRemoteAddress()
, participants);
std::shared_ptr<ChatRoomModel> chatRoomModel= CoreManager::getInstance()->getTimelineListModel()->getChatRoomModel(chatRoom, false);
if(chatRoomModel)
chatRoomModel->callEnded(mCall);
if(model){
model->callEnded(mCall);
}else{// No chat rooms have been associated for this call. Search one in current chat room list
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
std::shared_ptr<linphone::ChatRoomParams> params = core->createDefaultChatRoomParams();
std::list<std::shared_ptr<linphone::Address>> participants;
auto chatRoom = core->searchChatRoom(params, mCall->getCallLog()->getLocalAddress()
, mCall->getRemoteAddress()
, participants);
std::shared_ptr<ChatRoomModel> chatRoomModel= CoreManager::getInstance()->getTimelineListModel()->getChatRoomModel(chatRoom, false);
if(chatRoomModel)
chatRoomModel->callEnded(mCall);
}
}
}
void CallModel::setRemoteDisplayName(const std::string& name){
mRemoteAddress->setDisplayName(name);
auto callLog = mCall->getCallLog();
if(name!= "") {
auto core = CoreManager::getInstance()->getCore();
callLog->setRemoteAddress(Utils::interpretUrl(getFullPeerAddress()));
if(mCall) {
auto callLog = mCall->getCallLog();
if(name!= "") {
auto core = CoreManager::getInstance()->getCore();
callLog->setRemoteAddress(Utils::interpretUrl(getFullPeerAddress()));
}
}
emit fullPeerAddressChanged();
ChatRoomModel * model = getChatRoomModel();
@ -780,41 +821,56 @@ std::shared_ptr<linphone::Address> CallModel::getRemoteAddress()const{
// -----------------------------------------------------------------------------
CallModel::CallEncryption CallModel::getEncryption () const {
return static_cast<CallEncryption>(mCall->getCurrentParams()->getMediaEncryption());
if(mCall)
return static_cast<CallEncryption>(mCall->getCurrentParams()->getMediaEncryption());
else
return CallEncryptionNone;
}
bool CallModel::isSecured () const {
shared_ptr<const linphone::CallParams> params = mCall->getCurrentParams();
linphone::MediaEncryption encryption = params->getMediaEncryption();
return (
encryption == linphone::MediaEncryption::ZRTP && mCall->getAuthenticationTokenVerified()
) || encryption == linphone::MediaEncryption::SRTP || encryption == linphone::MediaEncryption::DTLS;
if(mCall){
shared_ptr<const linphone::CallParams> params = mCall->getCurrentParams();
linphone::MediaEncryption encryption = params->getMediaEncryption();
return (
encryption == linphone::MediaEncryption::ZRTP && mCall->getAuthenticationTokenVerified()
) || encryption == linphone::MediaEncryption::SRTP || encryption == linphone::MediaEncryption::DTLS;
}else
return false;
}
// -----------------------------------------------------------------------------
QString CallModel::getLocalSas () const {
QString token = Utils::coreStringToAppString(mCall->getAuthenticationToken());
return mCall->getDir() == linphone::Call::Dir::Incoming ? token.left(2).toUpper() : token.right(2).toUpper();
if(mCall){
QString token = Utils::coreStringToAppString(mCall->getAuthenticationToken());
return mCall->getDir() == linphone::Call::Dir::Incoming ? token.left(2).toUpper() : token.right(2).toUpper();
}else
return "";
}
QString CallModel::getRemoteSas () const {
QString token = Utils::coreStringToAppString(mCall->getAuthenticationToken());
return mCall->getDir() != linphone::Call::Dir::Incoming ? token.left(2).toUpper() : token.right(2).toUpper();
if(mCall){
QString token = Utils::coreStringToAppString(mCall->getAuthenticationToken());
return mCall->getDir() != linphone::Call::Dir::Incoming ? token.left(2).toUpper() : token.right(2).toUpper();
}else
return "";
}
// -----------------------------------------------------------------------------
QString CallModel::getSecuredString () const {
switch (mCall->getCurrentParams()->getMediaEncryption()) {
case linphone::MediaEncryption::SRTP:
return QStringLiteral("SRTP");
case linphone::MediaEncryption::ZRTP:
return QStringLiteral("ZRTP");
case linphone::MediaEncryption::DTLS:
return QStringLiteral("DTLS");
case linphone::MediaEncryption::None:
break;
if(mCall){
switch (mCall->getCurrentParams()->getMediaEncryption()) {
case linphone::MediaEncryption::SRTP:
return QStringLiteral("SRTP");
case linphone::MediaEncryption::ZRTP:
return QStringLiteral("ZRTP");
case linphone::MediaEncryption::DTLS:
return QStringLiteral("DTLS");
case linphone::MediaEncryption::None:
break;
}
}
return QString("");
@ -840,75 +896,77 @@ static inline QVariantMap createStat (const QString &key, const QString &value)
}
void CallModel::updateStats (const shared_ptr<const linphone::CallStats> &callStats, QVariantList &statsList) {
shared_ptr<const linphone::CallParams> params = mCall->getCurrentParams();
shared_ptr<const linphone::PayloadType> payloadType;
switch (callStats->getType()) {
case linphone::StreamType::Audio:
payloadType = params->getUsedAudioPayloadType();
break;
case linphone::StreamType::Video:
payloadType = params->getUsedVideoPayloadType();
break;
default:
return;
}
QString family;
switch (callStats->getIpFamilyOfRemote()) {
case linphone::AddressFamily::Inet:
family = QStringLiteral("IPv4");
break;
case linphone::AddressFamily::Inet6:
family = QStringLiteral("IPv6");
break;
default:
family = QStringLiteral("Unknown");
break;
}
statsList.clear();
statsList << createStat(tr("callStatsCodec"), payloadType
? QStringLiteral("%1 / %2kHz").arg(Utils::coreStringToAppString(payloadType->getMimeType())).arg(payloadType->getClockRate() / 1000)
: QString(""));
statsList << createStat(tr("callStatsUploadBandwidth"), QStringLiteral("%1 kbits/s").arg(int(callStats->getUploadBandwidth())));
statsList << createStat(tr("callStatsDownloadBandwidth"), QStringLiteral("%1 kbits/s").arg(int(callStats->getDownloadBandwidth())));
statsList << createStat(tr("callStatsIceState"), iceStateToString(callStats->getIceState()));
statsList << createStat(tr("callStatsIpFamily"), family);
statsList << createStat(tr("callStatsSenderLossRate"), QStringLiteral("%1 %").arg(static_cast<double>(callStats->getSenderLossRate())));
statsList << createStat(tr("callStatsReceiverLossRate"), QStringLiteral("%1 %").arg(static_cast<double>(callStats->getReceiverLossRate())));
switch (callStats->getType()) {
case linphone::StreamType::Audio:
statsList << createStat(tr("callStatsJitterBuffer"), QStringLiteral("%1 ms").arg(callStats->getJitterBufferSizeMs()));
break;
case linphone::StreamType::Video: {
statsList << createStat(tr("callStatsEstimatedDownloadBandwidth"), QStringLiteral("%1 kbits/s").arg(int(callStats->getEstimatedDownloadBandwidth())));
const QString sentVideoDefinitionName = Utils::coreStringToAppString(params->getSentVideoDefinition()->getName());
const QString sentVideoDefinition = QStringLiteral("%1x%2")
.arg(params->getSentVideoDefinition()->getWidth())
.arg(params->getSentVideoDefinition()->getHeight());
statsList << createStat(tr("callStatsSentVideoDefinition"), sentVideoDefinition == sentVideoDefinitionName
? sentVideoDefinition
: QStringLiteral("%1 (%2)").arg(sentVideoDefinition).arg(sentVideoDefinitionName));
const QString receivedVideoDefinitionName = Utils::coreStringToAppString(params->getReceivedVideoDefinition()->getName());
const QString receivedVideoDefinition = QString("%1x%2")
.arg(params->getReceivedVideoDefinition()->getWidth())
.arg(params->getReceivedVideoDefinition()->getHeight());
statsList << createStat(tr("callStatsReceivedVideoDefinition"), receivedVideoDefinition == receivedVideoDefinitionName
? receivedVideoDefinition
: QString("%1 (%2)").arg(receivedVideoDefinition).arg(receivedVideoDefinitionName));
statsList << createStat(tr("callStatsReceivedFramerate"), QStringLiteral("%1 FPS").arg(static_cast<double>(params->getReceivedFramerate())));
statsList << createStat(tr("callStatsSentFramerate"), QStringLiteral("%1 FPS").arg(static_cast<double>(params->getSentFramerate())));
} break;
default:
break;
if(mCall){
shared_ptr<const linphone::CallParams> params = mCall->getCurrentParams();
shared_ptr<const linphone::PayloadType> payloadType;
switch (callStats->getType()) {
case linphone::StreamType::Audio:
payloadType = params->getUsedAudioPayloadType();
break;
case linphone::StreamType::Video:
payloadType = params->getUsedVideoPayloadType();
break;
default:
return;
}
QString family;
switch (callStats->getIpFamilyOfRemote()) {
case linphone::AddressFamily::Inet:
family = QStringLiteral("IPv4");
break;
case linphone::AddressFamily::Inet6:
family = QStringLiteral("IPv6");
break;
default:
family = QStringLiteral("Unknown");
break;
}
statsList.clear();
statsList << createStat(tr("callStatsCodec"), payloadType
? QStringLiteral("%1 / %2kHz").arg(Utils::coreStringToAppString(payloadType->getMimeType())).arg(payloadType->getClockRate() / 1000)
: QString(""));
statsList << createStat(tr("callStatsUploadBandwidth"), QStringLiteral("%1 kbits/s").arg(int(callStats->getUploadBandwidth())));
statsList << createStat(tr("callStatsDownloadBandwidth"), QStringLiteral("%1 kbits/s").arg(int(callStats->getDownloadBandwidth())));
statsList << createStat(tr("callStatsIceState"), iceStateToString(callStats->getIceState()));
statsList << createStat(tr("callStatsIpFamily"), family);
statsList << createStat(tr("callStatsSenderLossRate"), QStringLiteral("%1 %").arg(static_cast<double>(callStats->getSenderLossRate())));
statsList << createStat(tr("callStatsReceiverLossRate"), QStringLiteral("%1 %").arg(static_cast<double>(callStats->getReceiverLossRate())));
switch (callStats->getType()) {
case linphone::StreamType::Audio:
statsList << createStat(tr("callStatsJitterBuffer"), QStringLiteral("%1 ms").arg(callStats->getJitterBufferSizeMs()));
break;
case linphone::StreamType::Video: {
statsList << createStat(tr("callStatsEstimatedDownloadBandwidth"), QStringLiteral("%1 kbits/s").arg(int(callStats->getEstimatedDownloadBandwidth())));
const QString sentVideoDefinitionName = Utils::coreStringToAppString(params->getSentVideoDefinition()->getName());
const QString sentVideoDefinition = QStringLiteral("%1x%2")
.arg(params->getSentVideoDefinition()->getWidth())
.arg(params->getSentVideoDefinition()->getHeight());
statsList << createStat(tr("callStatsSentVideoDefinition"), sentVideoDefinition == sentVideoDefinitionName
? sentVideoDefinition
: QStringLiteral("%1 (%2)").arg(sentVideoDefinition).arg(sentVideoDefinitionName));
const QString receivedVideoDefinitionName = Utils::coreStringToAppString(params->getReceivedVideoDefinition()->getName());
const QString receivedVideoDefinition = QString("%1x%2")
.arg(params->getReceivedVideoDefinition()->getWidth())
.arg(params->getReceivedVideoDefinition()->getHeight());
statsList << createStat(tr("callStatsReceivedVideoDefinition"), receivedVideoDefinition == receivedVideoDefinitionName
? receivedVideoDefinition
: QString("%1 (%2)").arg(receivedVideoDefinition).arg(receivedVideoDefinitionName));
statsList << createStat(tr("callStatsReceivedFramerate"), QStringLiteral("%1 FPS").arg(static_cast<double>(params->getReceivedFramerate())));
statsList << createStat(tr("callStatsSentFramerate"), QStringLiteral("%1 FPS").arg(static_cast<double>(params->getSentFramerate())));
} break;
default:
break;
}
}
}

View file

@ -26,54 +26,56 @@
#include "../search/SearchHandler.hpp"
// =============================================================================
class ConferenceModel;
class ContactModel;
class ChatRoomModel;
class CallModel : public QObject {
Q_OBJECT;
Q_OBJECT
Q_PROPERTY(QString peerAddress READ getPeerAddress CONSTANT);
Q_PROPERTY(QString localAddress READ getLocalAddress CONSTANT);
Q_PROPERTY(QString fullPeerAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged);
Q_PROPERTY(QString fullLocalAddress READ getFullLocalAddress CONSTANT);
Q_PROPERTY(QString peerAddress READ getPeerAddress CONSTANT)
Q_PROPERTY(QString localAddress READ getLocalAddress CONSTANT)
Q_PROPERTY(QString fullPeerAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged)
Q_PROPERTY(QString fullLocalAddress READ getFullLocalAddress CONSTANT)
Q_PROPERTY(ContactModel *contactModel READ getContactModel CONSTANT )
Q_PROPERTY(ChatRoomModel * chatRoomModel READ getChatRoomModel CONSTANT)
Q_PROPERTY(CallStatus status READ getStatus NOTIFY statusChanged);
Q_PROPERTY(QString callError READ getCallError NOTIFY callErrorChanged);
Q_PROPERTY(CallStatus status READ getStatus NOTIFY statusChanged)
Q_PROPERTY(QString callError READ getCallError NOTIFY callErrorChanged)
Q_PROPERTY(bool isOutgoing READ isOutgoing CONSTANT);
Q_PROPERTY(bool isOutgoing READ isOutgoing CONSTANT)
Q_PROPERTY(bool isInConference READ isInConference NOTIFY isInConferenceChanged);
Q_PROPERTY(bool isInConference READ isInConference NOTIFY isInConferenceChanged)
Q_PROPERTY(bool isConference READ isConference CONSTANT)
Q_PROPERTY(int duration READ getDuration CONSTANT); // Constants but called with a timer in qml.
Q_PROPERTY(float quality READ getQuality CONSTANT);
Q_PROPERTY(float speakerVu READ getSpeakerVu CONSTANT);
Q_PROPERTY(float microVu READ getMicroVu CONSTANT);
Q_PROPERTY(int duration READ getDuration CONSTANT) // Constants but called with a timer in qml.
Q_PROPERTY(float quality READ getQuality CONSTANT)
Q_PROPERTY(float speakerVu READ getSpeakerVu CONSTANT)
Q_PROPERTY(float microVu READ getMicroVu CONSTANT)
Q_PROPERTY(bool speakerMuted READ getSpeakerMuted WRITE setSpeakerMuted NOTIFY speakerMutedChanged);
Q_PROPERTY(bool microMuted READ getMicroMuted WRITE setMicroMuted NOTIFY microMutedChanged);
Q_PROPERTY(bool speakerMuted READ getSpeakerMuted WRITE setSpeakerMuted NOTIFY speakerMutedChanged)
Q_PROPERTY(bool microMuted READ getMicroMuted WRITE setMicroMuted NOTIFY microMutedChanged)
Q_PROPERTY(float speakerVolumeGain READ getSpeakerVolumeGain WRITE setSpeakerVolumeGain NOTIFY speakerVolumeGainChanged);
Q_PROPERTY(float microVolumeGain READ getMicroVolumeGain WRITE setMicroVolumeGain NOTIFY microVolumeGainChanged);
Q_PROPERTY(float speakerVolumeGain READ getSpeakerVolumeGain WRITE setSpeakerVolumeGain NOTIFY speakerVolumeGainChanged)
Q_PROPERTY(float microVolumeGain READ getMicroVolumeGain WRITE setMicroVolumeGain NOTIFY microVolumeGainChanged)
Q_PROPERTY(bool pausedByUser READ getPausedByUser WRITE setPausedByUser NOTIFY statusChanged);
Q_PROPERTY(bool videoEnabled READ getVideoEnabled WRITE setVideoEnabled NOTIFY statusChanged);
Q_PROPERTY(bool pausedByUser READ getPausedByUser WRITE setPausedByUser NOTIFY statusChanged)
Q_PROPERTY(bool videoEnabled READ getVideoEnabled WRITE setVideoEnabled NOTIFY statusChanged)
Q_PROPERTY(bool updating READ getUpdating NOTIFY statusChanged)
Q_PROPERTY(bool recording READ getRecording NOTIFY recordingChanged);
Q_PROPERTY(bool recording READ getRecording NOTIFY recordingChanged)
Q_PROPERTY(QVariantList audioStats READ getAudioStats NOTIFY statsUpdated);
Q_PROPERTY(QVariantList videoStats READ getVideoStats NOTIFY statsUpdated);
Q_PROPERTY(QVariantList audioStats READ getAudioStats NOTIFY statsUpdated)
Q_PROPERTY(QVariantList videoStats READ getVideoStats NOTIFY statsUpdated)
Q_PROPERTY(CallEncryption encryption READ getEncryption NOTIFY securityUpdated);
Q_PROPERTY(bool isSecured READ isSecured NOTIFY securityUpdated);
Q_PROPERTY(QString localSas READ getLocalSas NOTIFY securityUpdated);
Q_PROPERTY(QString remoteSas READ getRemoteSas NOTIFY securityUpdated);
Q_PROPERTY(QString securedString READ getSecuredString NOTIFY securityUpdated);
Q_PROPERTY(CallEncryption encryption READ getEncryption NOTIFY securityUpdated)
Q_PROPERTY(bool isSecured READ isSecured NOTIFY securityUpdated)
Q_PROPERTY(QString localSas READ getLocalSas NOTIFY securityUpdated)
Q_PROPERTY(QString remoteSas READ getRemoteSas NOTIFY securityUpdated)
Q_PROPERTY(QString securedString READ getSecuredString NOTIFY securityUpdated)
Q_PROPERTY(QString transferAddress READ getTransferAddress WRITE setTransferAddress NOTIFY transferAddressChanged);
Q_PROPERTY(QString transferAddress READ getTransferAddress WRITE setTransferAddress NOTIFY transferAddressChanged)
@ -109,12 +111,13 @@ public:
QString getFullLocalAddress () const;
ContactModel *getContactModel() const;
ChatRoomModel * getChatRoomModel() const;
std::shared_ptr<ConferenceModel> getConferenceModel() const;
bool isInConference () const {
return mIsInConference;
}
bool isConference () const;
void setRecordFile (const std::shared_ptr<linphone::CallParams> &callParams);
static void setRecordFile (const std::shared_ptr<linphone::CallParams> &callParams, const QString &to);
@ -197,7 +200,7 @@ private:
CallStatus getStatus () const;
bool isOutgoing () const {
return mCall->getDir() == linphone::Call::Dir::Outgoing;
return mCall && mCall->getDir() == linphone::Call::Dir::Outgoing;
}
void updateIsInConference ();
@ -268,6 +271,7 @@ private:
QVariantList mVideoStats;
std::shared_ptr<SearchHandler> mSearch;
QString mTransferAddress;
std::shared_ptr<ConferenceModel> mConferenceModel;
};
#endif // CALL_MODEL_H_

View file

@ -26,6 +26,8 @@
#include "components/call/CallModel.hpp"
#include "components/conference/ConferenceAddModel.hpp"
#include "components/conference/ConferenceHelperModel.hpp"
#include "components/conference/ConferenceModel.hpp"
#include "components/conferenceInfo/ConferenceInfoModel.hpp"
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "components/participant/ParticipantModel.hpp"
@ -188,8 +190,8 @@ void CallsListModel::launchSecureAudioCall (const QString &sipAddress, LinphoneE
CallModel::prepareTransfert(core->inviteAddressWithParams(address, params), prepareTransfertAddress);
}
void CallsListModel::launchVideoCall (const QString &sipAddress, const QString& prepareTransfertAddress) const {
CoreManager::getInstance()->getTimelineListModel()->mAutoSelectAfterCreation = true;
void CallsListModel::launchVideoCall (const QString &sipAddress, const QString& prepareTransfertAddress, const bool& autoSelectAfterCreation) const {
CoreManager::getInstance()->getTimelineListModel()->mAutoSelectAfterCreation = autoSelectAfterCreation;
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
if (!core->videoSupported()) {
qWarning() << QStringLiteral("Unable to launch video call. (Video not supported.) Launching audio call...");
@ -378,6 +380,78 @@ QVariantMap CallsListModel::createChatRoom(const QString& subject, const int& se
return result;
}
QVariantMap CallsListModel::createConference(ConferenceInfoModel * conferenceInfo, const int& securityLevel, const int& inviteMode, const bool& selectAfterCreation) {
QVariantMap result;
CoreManager::getInstance()->getTimelineListModel()->mAutoSelectAfterCreation = selectAfterCreation;
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
std::shared_ptr<linphone::Conference> conference;
QList< std::shared_ptr<linphone::Address>> admins;
std::shared_ptr<TimelineModel> timeline;
auto timelineList = CoreManager::getInstance()->getTimelineListModel();
qInfo() << "Conference creation of " << conferenceInfo->getSubject() << " at " << securityLevel << " security";// and with " << conferenceInfo->getConferenceInfo()->getParticipants().size();
std::shared_ptr<linphone::ConferenceParams> params = core->createConferenceParams();
std::list <shared_ptr<linphone::Address> > participants = conferenceInfo->getConferenceInfo()->getParticipants();
std::shared_ptr<const linphone::Address> localAddress;
/*
for(auto p : participants){
ParticipantModel* participant = p.value<ParticipantModel*>();
std::shared_ptr<linphone::Address> address;
if(participant) {
address = Utils::interpretUrl(participant->getSipAddress());
if(participant->getAdminStatus())
admins << address;
}else{
QString participant = p.toString();
if( participant != "")
address = Utils::interpretUrl(participant);
}
if( address)
chatRoomParticipants.push_back( address );
}*/
auto proxy = core->getDefaultProxyConfig();
params->setVideoEnabled(true);
params->setStartTime(conferenceInfo->getConferenceInfo()->getDateTime());
params->setEndTime(conferenceInfo->getConferenceInfo()->getDateTime()+conferenceInfo->getConferenceInfo()->getDuration()*60*1000);
//params->setDescription(conferenceInfo->getConferenceInfo()->getDescription());
//params->enableEncryption(securityLevel>0);
// if( securityLevel>0){
// params->enableEncryption(true);
// }else
// params->setBackend(linphone::ChatRoomBackend::Basic);
// params->enableGroup( subject!="" );
if(participants.size() > 0) {
params->setSubject(conferenceInfo->getSubject() != ""?Utils::appStringToCoreString(conferenceInfo->getSubject()):"Dummy Subject");
if( !conference) {
core->createConferenceOnServer(params, localAddress, participants);
/*
//conference = core->createConferenceWithParams(params);
if(conference != nullptr && admins.size() > 0){
for(auto a : admins) {
auto p = conference->findParticipant(a);
if( p )
conference->setParticipantAdminStatus(p, true);
else
qWarning() <<"Cannot set admin for " << a->asString().c_str() << ". It is not found in conference.";
}
}
// Warning: Should not be needed but SDK doesn't ref it
mConferences.append(std::make_shared<ConferenceModel>(conference));
//ChatRoomInitializer::setAdminsAsync(params->getSubject(), params->getBackend(), params->groupEnabled(), admins );
// timeline = timelineList->getTimeline(conference, false);
*/
}
}
//result["created"] = (conference != nullptr);
return result;
}
// -----------------------------------------------------------------------------
@ -523,6 +597,31 @@ void CallsListModel::addCall (const shared_ptr<linphone::Call> &call) {
emit layoutChanged();
}
void CallsListModel::addDummyCall () {
QQuickWindow *callsWindow = App::getInstance()->getCallsWindow();
if (callsWindow) {
App::smartShowWindow(callsWindow);
}
CallModel *callModel = new CallModel(nullptr);
qInfo() << QStringLiteral("Add call:") << callModel->getFullLocalAddress() << callModel->getFullPeerAddress();
App::getInstance()->getEngine()->setObjectOwnership(callModel, QQmlEngine::CppOwnership);
// This connection is (only) useful for `CallsListProxyModel`.
QObject::connect(callModel, &CallModel::isInConferenceChanged, this, [this, callModel](bool) {
int id = findCallIndex(mList, *callModel);
emit dataChanged(index(id, 0), index(id, 0));
});
int row = mList.count();
beginInsertRows(QModelIndex(), row, row);
mList << callModel;
endInsertRows();
emit layoutChanged();
}
void CallsListModel::removeCall (const shared_ptr<linphone::Call> &call) {
CallModel *callModel;

View file

@ -31,6 +31,8 @@
class ChatRoomModel;
class CoreHandlers;
class ConferenceModel;
class ConferenceInfoModel;
class CallsListModel : public QAbstractListModel {
Q_OBJECT
@ -49,7 +51,7 @@ public:
Q_INVOKABLE void launchAudioCall (const QString &sipAddress, const QString& prepareTransfertAddress = "", const QHash<QString, QString> &headers = {}) const;
Q_INVOKABLE void launchSecureAudioCall (const QString &sipAddress, LinphoneEnums::MediaEncryption encryption, const QHash<QString, QString> &headers = {}, const QString& prepareTransfertAddress = "") const;
Q_INVOKABLE void launchVideoCall (const QString &sipAddress, const QString& prepareTransfertAddress = "") const;
Q_INVOKABLE void launchVideoCall (const QString &sipAddress, const QString& prepareTransfertAddress = "", const bool& autoSelectAfterCreation = true) const;
Q_INVOKABLE ChatRoomModel* launchSecureChat (const QString &sipAddress) const;
Q_INVOKABLE QVariantMap launchChat(const QString &sipAddress, const int& securityLevel) const;
Q_INVOKABLE ChatRoomModel* createChat (const QString &participantAddress) const;
@ -58,6 +60,9 @@ public:
QVariantMap createChatRoom(const QString& subject, const int& securityLevel, std::shared_ptr<linphone::Address> localAddress, const QVariantList& participants, const bool& selectAfterCreation) const;
Q_INVOKABLE QVariantMap createChatRoom(const QString& subject, const int& securityLevel, const QVariantList& participants, const bool& selectAfterCreation) const;
//Q_INVOKABLE QVariantMap createConference(const QString& subject, const int& securityLevel, const QVariantList& participants, const int& inviteMode, const bool& selectAfterCreation);
Q_INVOKABLE QVariantMap createConference(ConferenceInfoModel * conferenceInfo, const int& securityLevel, const int& inviteMode, const bool& selectAfterCreation);
Q_INVOKABLE int getRunningCallsNumber () const;
@ -80,10 +85,12 @@ private:
void handleCallStateChanged (const std::shared_ptr<linphone::Call> &call, linphone::Call::State state);
void addCall (const std::shared_ptr<linphone::Call> &call);
void addDummyCall ();
void removeCall (const std::shared_ptr<linphone::Call> &call);
void removeCallCb (CallModel *callModel);
QList<CallModel *> mList;
QList<std::shared_ptr<ConferenceModel>> mConferences;
std::shared_ptr<CoreHandlers> mCoreHandlers;
};

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
@ -18,131 +18,30 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QDateTime>
#include <QtDebug>
#include "ConferenceModel.hpp"
#include <QQmlApplicationEngine>
#include <QDesktopServices>
#include <QImageReader>
#include <QMessageBox>
#include "app/App.hpp"
#include "components/call/CallModel.hpp"
#include "components/calls/CallsListModel.hpp"
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "components/notifier/Notifier.hpp"
#include "components/settings/SettingsModel.hpp"
#include "utils/MediastreamerUtils.hpp"
#include "utils/Utils.hpp"
#include "app/paths/Paths.hpp"
#include "app/providers/ThumbnailProvider.hpp"
#include "ConferenceModel.hpp"
#include "utils/QExifImageHeader.hpp"
#include "utils/Utils.hpp"
#include "utils/Constants.hpp"
#include "components/Components.hpp"
// =============================================================================
using namespace std;
ConferenceModel::ConferenceModel (QObject *parent) : QSortFilterProxyModel(parent) {
QObject::connect(this, &ConferenceModel::rowsRemoved, [this] { // Warning : called before model remove its items
emit countChanged(rowCount());
});
QObject::connect(this, &ConferenceModel::rowsInserted, [this] {
emit countChanged(rowCount());
});
setSourceModel(CoreManager::getInstance()->getCallsListModel());
emit conferenceChanged();
QObject::connect(
CoreManager::getInstance()->getHandlers().get(), &CoreHandlers::callStateChanged,
this, [this] { emit conferenceChanged(); });
}
// Show all paraticpants thar should be, will be or are still in conference
bool ConferenceModel::filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const {
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
const CallModel *callModel = index.data().value<CallModel *>();
return callModel->getCall()->getParams()->getLocalConferenceMode() || callModel->getCall()->getCurrentParams()->getLocalConferenceMode();
}
// -----------------------------------------------------------------------------
void ConferenceModel::terminate () {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
core->terminateConference();
for (const auto &call : core->getCalls()) {
if (call->getParams()->getLocalConferenceMode())// Terminate all call where participants are or will be in conference
call->terminate();
}
ConferenceModel::ConferenceModel(std::shared_ptr<linphone::Conference> conference){
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
mConference = conference;
}
// -----------------------------------------------------------------------------
void ConferenceModel::startRecording () {
if (mRecording)
return;
qInfo() << QStringLiteral("Start recording conference:") << this;
CoreManager *coreManager = CoreManager::getInstance();
mLastRecordFile =
QStringLiteral("%1%2.mkv")
.arg(coreManager->getSettingsModel()->getSavedCallsFolder())
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss"));
coreManager->getCore()->startConferenceRecording(Utils::appStringToCoreString(mLastRecordFile) );
mRecording = true;
emit recordingChanged(true);
}
void ConferenceModel::stopRecording () {
if (!mRecording)
return;
qInfo() << QStringLiteral("Stop recording conference:") << this;
mRecording = false;
CoreManager::getInstance()->getCore()->stopConferenceRecording();
App::getInstance()->getNotifier()->notifyRecordingCompleted(mLastRecordFile);
emit recordingChanged(false);
}
// -----------------------------------------------------------------------------
bool ConferenceModel::getMicroMuted () const {
return !CoreManager::getInstance()->getCore()->micEnabled();
}
void ConferenceModel::setMicroMuted (bool status) {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
if (status == core->micEnabled()) {
core->enableMic(!status);
emit microMutedChanged(status);
}
}
// -----------------------------------------------------------------------------
bool ConferenceModel::getRecording () const {
return mRecording;
}
// -----------------------------------------------------------------------------
float ConferenceModel::getMicroVu () const {
return MediastreamerUtils::computeVu(
CoreManager::getInstance()->getCore()->getConferenceLocalInputVolume()
);
}
// -----------------------------------------------------------------------------
void ConferenceModel::leave () {
CoreManager::getInstance()->getCore()->leaveConference();
emit conferenceChanged();
}
void ConferenceModel::join () {
CoreManager::getInstance()->getCore()->enterConference();
emit conferenceChanged();
}
bool ConferenceModel::isInConference () const {
return CoreManager::getInstance()->getCore()->isInConference();
std::shared_ptr<linphone::Conference> ConferenceModel::getConference()const{
return mConference;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
@ -21,59 +21,24 @@
#ifndef CONFERENCE_MODEL_H_
#define CONFERENCE_MODEL_H_
#include <QSortFilterProxyModel>
#include <linphone++/linphone.hh>
// =============================================================================
#include <QObject>
#include <QDateTime>
#include <QString>
class CallModel;
class ConferenceModel : public QSortFilterProxyModel {
Q_OBJECT;
Q_PROPERTY(int count READ getCount NOTIFY countChanged);
Q_PROPERTY(bool microMuted READ getMicroMuted WRITE setMicroMuted NOTIFY microMutedChanged);
Q_PROPERTY(float microVu READ getMicroVu CONSTANT);
Q_PROPERTY(bool recording READ getRecording NOTIFY recordingChanged);
Q_PROPERTY(bool isInConf READ isInConference NOTIFY conferenceChanged);
class ConferenceModel : public QObject{
Q_OBJECT
public:
ConferenceModel (QObject *parent = Q_NULLPTR);
ConferenceModel(std::shared_ptr<linphone::Conference> content);
protected:
bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override;
Q_INVOKABLE void terminate ();
Q_INVOKABLE void startRecording ();
Q_INVOKABLE void stopRecording ();
Q_INVOKABLE void join ();
Q_INVOKABLE void leave ();
signals:
void countChanged (int count);
void microMutedChanged (bool status);
void recordingChanged (bool status);
void conferenceChanged ();
std::shared_ptr<linphone::Conference> getConference()const;
private:
int getCount () const {
return rowCount();
}
bool getMicroMuted () const;
void setMicroMuted (bool status);
float getMicroVu () const;
bool isInConference () const;
bool getRecording () const;
bool mRecording = false;
QString mLastRecordFile;
std::shared_ptr<linphone::Conference> mConference;
};
Q_DECLARE_METATYPE(std::shared_ptr<ConferenceModel>)
#endif // CONFERENCE_MODEL_H_
#endif

View file

@ -0,0 +1,148 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 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/>.
*/
#include <QDateTime>
#include <QtDebug>
#include "app/App.hpp"
#include "components/call/CallModel.hpp"
#include "components/calls/CallsListModel.hpp"
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "components/notifier/Notifier.hpp"
#include "components/settings/SettingsModel.hpp"
#include "utils/MediastreamerUtils.hpp"
#include "utils/Utils.hpp"
#include "ConferenceProxyModel.hpp"
// =============================================================================
using namespace std;
ConferenceProxyModel::ConferenceProxyModel (QObject *parent) : QSortFilterProxyModel(parent) {
QObject::connect(this, &ConferenceProxyModel::rowsRemoved, [this] { // Warning : called before model remove its items
emit countChanged(rowCount());
});
QObject::connect(this, &ConferenceProxyModel::rowsInserted, [this] {
emit countChanged(rowCount());
});
setSourceModel(CoreManager::getInstance()->getCallsListModel());
emit conferenceChanged();
QObject::connect(
CoreManager::getInstance()->getHandlers().get(), &CoreHandlers::callStateChanged,
this, [this] { emit conferenceChanged(); });
}
// Show all paraticpants thar should be, will be or are still in conference
bool ConferenceProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const {
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
const CallModel *callModel = index.data().value<CallModel *>();
return callModel->getCall()->getParams()->getLocalConferenceMode() || callModel->getCall()->getCurrentParams()->getLocalConferenceMode();
}
// -----------------------------------------------------------------------------
void ConferenceProxyModel::terminate () {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
core->terminateConference();
for (const auto &call : core->getCalls()) {
if (call->getParams()->getLocalConferenceMode())// Terminate all call where participants are or will be in conference
call->terminate();
}
}
// -----------------------------------------------------------------------------
void ConferenceProxyModel::startRecording () {
if (mRecording)
return;
qInfo() << QStringLiteral("Start recording conference:") << this;
CoreManager *coreManager = CoreManager::getInstance();
mLastRecordFile =
QStringLiteral("%1%2.mkv")
.arg(coreManager->getSettingsModel()->getSavedCallsFolder())
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss"));
coreManager->getCore()->startConferenceRecording(Utils::appStringToCoreString(mLastRecordFile) );
mRecording = true;
emit recordingChanged(true);
}
void ConferenceProxyModel::stopRecording () {
if (!mRecording)
return;
qInfo() << QStringLiteral("Stop recording conference:") << this;
mRecording = false;
CoreManager::getInstance()->getCore()->stopConferenceRecording();
App::getInstance()->getNotifier()->notifyRecordingCompleted(mLastRecordFile);
emit recordingChanged(false);
}
// -----------------------------------------------------------------------------
bool ConferenceProxyModel::getMicroMuted () const {
return !CoreManager::getInstance()->getCore()->micEnabled();
}
void ConferenceProxyModel::setMicroMuted (bool status) {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
if (status == core->micEnabled()) {
core->enableMic(!status);
emit microMutedChanged(status);
}
}
// -----------------------------------------------------------------------------
bool ConferenceProxyModel::getRecording () const {
return mRecording;
}
// -----------------------------------------------------------------------------
float ConferenceProxyModel::getMicroVu () const {
return MediastreamerUtils::computeVu(
CoreManager::getInstance()->getCore()->getConferenceLocalInputVolume()
);
}
// -----------------------------------------------------------------------------
void ConferenceProxyModel::leave () {
CoreManager::getInstance()->getCore()->leaveConference();
emit conferenceChanged();
}
void ConferenceProxyModel::join () {
CoreManager::getInstance()->getCore()->enterConference();
emit conferenceChanged();
}
bool ConferenceProxyModel::isInConference () const {
return CoreManager::getInstance()->getCore()->isInConference();
}

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 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/>.
*/
#ifndef CONFERENCE_PROXY_MODEL_H_
#define CONFERENCE_PROXY_MODEL_H_
#include <QSortFilterProxyModel>
// =============================================================================
class CallModel;
class ConferenceProxyModel : public QSortFilterProxyModel {
Q_OBJECT;
Q_PROPERTY(int count READ getCount NOTIFY countChanged);
Q_PROPERTY(bool microMuted READ getMicroMuted WRITE setMicroMuted NOTIFY microMutedChanged);
Q_PROPERTY(float microVu READ getMicroVu CONSTANT);
Q_PROPERTY(bool recording READ getRecording NOTIFY recordingChanged);
Q_PROPERTY(bool isInConf READ isInConference NOTIFY conferenceChanged);
public:
ConferenceProxyModel (QObject *parent = Q_NULLPTR);
protected:
bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override;
Q_INVOKABLE void terminate ();
Q_INVOKABLE void startRecording ();
Q_INVOKABLE void stopRecording ();
Q_INVOKABLE void join ();
Q_INVOKABLE void leave ();
signals:
void countChanged (int count);
void microMutedChanged (bool status);
void recordingChanged (bool status);
void conferenceChanged ();
private:
int getCount () const {
return rowCount();
}
bool getMicroMuted () const;
void setMicroMuted (bool status);
float getMicroVu () const;
bool isInConference () const;
bool getRecording () const;
bool mRecording = false;
QString mLastRecordFile;
};
#endif // CONFERENCE_MODEL_H_

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 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/>.
*/
#include <QQmlApplicationEngine>
#include <QQuickWindow>
#include <QTimer>
#include "app/App.hpp"
#include "components/conference/ConferenceAddModel.hpp"
#include "components/conference/ConferenceHelperModel.hpp"
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "components/settings/SettingsModel.hpp"
#include "utils/Utils.hpp"
#include "ConferenceInfoListModel.hpp"
#include "ConferenceInfoModel.hpp"
// =============================================================================
ConferenceInfoListModel::ConferenceInfoListModel (QObject *parent) : QAbstractListModel(parent) {
auto conferenceInfos = CoreManager::getInstance()->getCore()->getConferenceInformationList();
for(auto conferenceInfo : conferenceInfos){
mList << ConferenceInfoModel::create( conferenceInfo );
}
}
int ConferenceInfoListModel::rowCount (const QModelIndex &) const {
return mList.count();
}
QHash<int, QByteArray> ConferenceInfoListModel::roleNames () const {
QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "$conferenceInfo";
return roles;
}
QVariant ConferenceInfoListModel::data (const QModelIndex &index, int role) const {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mList.count())
return QVariant();
if (role == Qt::DisplayRole)
return QVariant::fromValue(mList[row].get());
//return QVariant();
}
// -----------------------------------------------------------------------------
bool ConferenceInfoListModel::removeRow (int row, const QModelIndex &parent) {
return removeRows(row, 1, parent);
}
bool ConferenceInfoListModel::removeRows (int row, int count, const QModelIndex &parent) {
int limit = row + count - 1;
if (row < 0 || count < 0 || limit >= mList.count())
return false;
beginRemoveRows(parent, row, limit);
for (int i = 0; i < count; ++i)
mList.takeAt(row)->deleteLater();
endRemoveRows();
return true;
}
// -----------------------------------------------------------------------------

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 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/>.
*/
#ifndef _CONFERENCE_INFO_LIST_MODEL_H_
#define _CONFERENCE_INFO_LIST_MODEL_H_
#include <linphone++/linphone.hh>
#include <QAbstractListModel>
// =============================================================================
class ConferenceInfoModel;
class ConferenceInfoListModel : public QAbstractListModel {
Q_OBJECT
public:
ConferenceInfoListModel (QObject *parent = Q_NULLPTR);
int rowCount (const QModelIndex &index = QModelIndex()) const override;
QHash<int, QByteArray> roleNames () const override;
QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override;
private:
bool removeRow (int row, const QModelIndex &parent = QModelIndex());
bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override;
QList<std::shared_ptr<ConferenceInfoModel>> mList;
};
#endif

View file

@ -0,0 +1,173 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 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/>.
*/
#include "ConferenceInfoModel.hpp"
#include <algorithm>
#include <QDateTime>
#include <QDesktopServices>
#include <QElapsedTimer>
#include <QFileInfo>
#include <QMimeDatabase>
#include <QTimer>
#include <QUuid>
#include <QMessageBox>
#include <QUrlQuery>
#include <QImageReader>
#include <qqmlapplicationengine.h>
#include "app/App.hpp"
#include "app/paths/Paths.hpp"
#include "app/providers/ThumbnailProvider.hpp"
#include "components/calls/CallsListModel.hpp"
#include "components/chat-events/ChatCallModel.hpp"
#include "components/chat-events/ChatEvent.hpp"
#include "components/chat-events/ChatMessageModel.hpp"
#include "components/chat-events/ChatNoticeModel.hpp"
#include "components/contact/ContactModel.hpp"
#include "components/contact/VcardModel.hpp"
#include "components/contacts/ContactsListModel.hpp"
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "components/notifier/Notifier.hpp"
#include "components/settings/AccountSettingsModel.hpp"
#include "components/settings/SettingsModel.hpp"
#include "components/participant/ParticipantModel.hpp"
#include "components/participant/ParticipantListModel.hpp"
#include "components/presence/Presence.hpp"
#include "components/recorder/RecorderManager.hpp"
#include "components/recorder/RecorderModel.hpp"
#include "components/timeline/TimelineModel.hpp"
#include "components/timeline/TimelineListModel.hpp"
#include "components/core/event-count-notifier/AbstractEventCountNotifier.hpp"
#include "utils/QExifImageHeader.hpp"
#include "utils/Utils.hpp"
#include "utils/Constants.hpp"
#include "utils/LinphoneEnums.hpp"
// =============================================================================
using namespace std;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
std::shared_ptr<ConferenceInfoModel> ConferenceInfoModel::create(std::shared_ptr<linphone::ConferenceInfo> conferenceInfo){
std::shared_ptr<ConferenceInfoModel> model = std::make_shared<ConferenceInfoModel>(conferenceInfo);
if(model){
//model->mSelf = model;
//chatRoom->addListener(model);
return model;
}else
return nullptr;
}
ConferenceInfoModel::ConferenceInfoModel (QObject * parent) : QObject(parent){
//App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
mConferenceInfo = linphone::Factory::get()->createConferenceInfo();
}
ConferenceInfoModel::ConferenceInfoModel (std::shared_ptr<linphone::ConferenceInfo> conferenceInfo, QObject * parent) : QObject(parent){
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
mConferenceInfo = conferenceInfo;
}
ConferenceInfoModel::~ConferenceInfoModel () {
}
std::shared_ptr<linphone::ConferenceInfo> ConferenceInfoModel::getConferenceInfo(){
return mConferenceInfo;
}
//------------------------------------------------------------------------------------------------
QDateTime ConferenceInfoModel::getDateTime() const{
return QDateTime::fromMSecsSinceEpoch(mConferenceInfo->getDateTime() * 1000);
}
int ConferenceInfoModel::getDuration() const{
return mConferenceInfo->getDuration();
}
QString ConferenceInfoModel::getOrganizer() const{
return QString::fromStdString(mConferenceInfo->getOrganizer()->asString());
}
QString ConferenceInfoModel::getSubject() const{
return QString::fromStdString(mConferenceInfo->getSubject());
}
QString ConferenceInfoModel::getDescription() const{
return QString::fromStdString(mConferenceInfo->getDescription());
}
QString ConferenceInfoModel::displayNamesToString()const{
QStringList txt;
for(auto participant : mConferenceInfo->getParticipants()){
if(participant){
QString displayName = Utils::getDisplayName(participant);
if(displayName != "")
txt << displayName;
}
}
//txt.removeFirst();// Remove me
return txt.join(", ");
}
QString ConferenceInfoModel::getUri() const{
return QString::fromStdString(mConferenceInfo->getUri()->asString());
}
//------------------------------------------------------------------------------------------------
void ConferenceInfoModel::setDateTime(const QDateTime& dateTime){
mConferenceInfo->setDateTime(dateTime.toMSecsSinceEpoch() / 1000);
emit dateTimeChanged();
}
void ConferenceInfoModel::setDuration(const int& duration){
mConferenceInfo->setDuration(duration);
emit durationChanged();
}
void ConferenceInfoModel::setSubject(const QString& subject){
mConferenceInfo->setSubject(subject.toStdString());
emit subjectChanged();
}
void ConferenceInfoModel::setOrganizer(const QString& organizerAddress){
mConferenceInfo->setOrganizer(Utils::interpretUrl(organizerAddress));
emit organizerChanged();
}
void ConferenceInfoModel::setDescription(const QString& description){
mConferenceInfo->setDescription(description.toStdString());
emit descriptionChanged();
}
void ConferenceInfoModel::setParticipants(ParticipantListModel * participants){
mConferenceInfo->setParticipants(participants->getParticipants());
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 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/>.
*/
#ifndef CONFERENCE_INFO_MODEL_H_
#define CONFERENCE_INFO_MODEL_H_
#include <linphone++/linphone.hh>
#include <QDateTime>
#include <QObject>
class ParticipantListModel;
class ConferenceInfoModel : public QObject{
Q_OBJECT
public:
Q_PROPERTY(QDateTime dateTime READ getDateTime WRITE setDateTime NOTIFY dateTimeChanged)
Q_PROPERTY(int duration READ getDuration WRITE setDuration NOTIFY durationChanged)
Q_PROPERTY(QString organizer READ getOrganizer WRITE setOrganizer NOTIFY organizerChanged)
Q_PROPERTY(QString subject READ getSubject WRITE setSubject NOTIFY subjectChanged)
Q_PROPERTY(QString description READ getDescription WRITE setDescription NOTIFY descriptionChanged)
Q_PROPERTY(QString displayNamesToString READ displayNamesToString NOTIFY participantsChanged)
Q_PROPERTY(QString uri READ getUri NOTIFY uriChanged)
//Q_PROPERTY(participants READ getParticipants WRITE setParticipants NOTIFY participantsChanged)
static std::shared_ptr<ConferenceInfoModel> create(std::shared_ptr<linphone::ConferenceInfo> conferenceInfo);
ConferenceInfoModel (QObject * parent = nullptr);
ConferenceInfoModel (std::shared_ptr<linphone::ConferenceInfo> conferenceInfo, QObject * parent = nullptr);
~ConferenceInfoModel ();
std::shared_ptr<linphone::ConferenceInfo> getConferenceInfo();
//-------------------------------
QDateTime getDateTime() const;
int getDuration() const;
QString getOrganizer() const;
QString getSubject() const;
QString getDescription() const;
Q_INVOKABLE QString displayNamesToString()const;
QString getUri() const;
void setDateTime(const QDateTime& dateTime);
void setDuration(const int& duration);
void setSubject(const QString& subject);
void setOrganizer(const QString& organizerAddress);
void setDescription(const QString& description);
Q_INVOKABLE void setParticipants(ParticipantListModel * participants);
signals:
void dateTimeChanged();
void durationChanged();
void organizerChanged();
void subjectChanged();
void descriptionChanged();
void participantsChanged();
void uriChanged();
private:
std::shared_ptr<linphone::ConferenceInfo> mConferenceInfo;
};
Q_DECLARE_METATYPE(std::shared_ptr<ConferenceInfoModel>)
#endif

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 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/>.
*/
#include "components/call/CallModel.hpp"
#include "components/core/CoreManager.hpp"
#include "ConferenceInfoListModel.hpp"
#include "ConferenceInfoProxyModel.hpp"
// =============================================================================
using namespace std;
ConferenceInfoProxyModel::ConferenceInfoProxyModel (QObject *parent) : QSortFilterProxyModel(parent) {
setSourceModel(new ConferenceInfoListModel());
sort(0);
}
bool ConferenceInfoProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const {
return true;
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 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/>.
*/
#ifndef CONFERENCE_INFO_PROXY_MODEL_H_
#define CONFERENCE_INFO_PROXY_MODEL_H_
#include <QSortFilterProxyModel>
#include "ConferenceInfoModel.hpp"
// =============================================================================
class QWindow;
class ConferenceInfoProxyModel : public QSortFilterProxyModel {
class ChatRoomModelFilter;
Q_OBJECT
public:
ConferenceInfoProxyModel (QObject *parent = Q_NULLPTR);
protected:
bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override;
//bool lessThan (const QModelIndex &left, const QModelIndex &right) const override;
private:
ConferenceInfoModel *getConferenceInfoModel() const;
void setConferenceInfoModel (ConferenceInfoModel *conferenceInfoModel);
std::shared_ptr<ConferenceInfoModel> mConferenceInfoModel;
};
#endif

View file

@ -323,3 +323,21 @@ void CoreHandlers::onEcCalibrationResult(
) {
emit ecCalibrationResult(status, delayMs);
}
//------------------------------ CONFERENCE INFO
void CoreHandlers::onConferenceInfoCreated(const std::shared_ptr<linphone::Core> & core, const std::shared_ptr<const linphone::ConferenceInfo> & conferenceInfo){
qWarning() << "onConferenceInfoCreated";
}
void CoreHandlers::onConferenceInfoOnSent(const std::shared_ptr<linphone::Core> & core, const std::shared_ptr<const linphone::ConferenceInfo> & conferenceInfo){
qWarning() << "onConferenceInfoOnSent";
}
void CoreHandlers::onConferenceInfoParticipantSent(const std::shared_ptr<linphone::Core> & core, const std::shared_ptr<const linphone::ConferenceInfo> & conferenceInfo, const std::shared_ptr<const linphone::Address> & participant){
qWarning() << "onConferenceInfoParticipantSent";
}
void CoreHandlers::onConferenceInfoParticipantError(const std::shared_ptr<linphone::Core> & core, const std::shared_ptr<const linphone::ConferenceInfo> & conferenceInfo, const std::shared_ptr<const linphone::Address> & participant, linphone::ConferenceInfoError error){
qWarning() << "onConferenceInfoParticipantError";
}

View file

@ -60,7 +60,6 @@ signals:
void setLastRemoteProvisioningState(const linphone::ConfiguringState &state);
private:
// ---------------------------------------------------------------------------
// Linphone callbacks.
// ---------------------------------------------------------------------------
@ -159,8 +158,13 @@ private:
const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Friend> &linphoneFriend
) override;
//void onRegistrationStateChanged (
void onRegistrationStateChanged (
const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ProxyConfig> &proxyConfig,
linphone::RegistrationState state,
const std::string &message
) override;
void onTransferStateChanged (
const std::shared_ptr<linphone::Core> &core,
@ -181,6 +185,13 @@ private:
int delayMs
) override;
// Conference Info
virtual void onConferenceInfoCreated(const std::shared_ptr<linphone::Core> & core, const std::shared_ptr<const linphone::ConferenceInfo> & conferenceInfo);
virtual void onConferenceInfoOnSent(const std::shared_ptr<linphone::Core> & core, const std::shared_ptr<const linphone::ConferenceInfo> & conferenceInfo);
virtual void onConferenceInfoParticipantSent(const std::shared_ptr<linphone::Core> & core, const std::shared_ptr<const linphone::ConferenceInfo> & conferenceInfo, const std::shared_ptr<const linphone::Address> & participant);
virtual void onConferenceInfoParticipantError(const std::shared_ptr<linphone::Core> & core, const std::shared_ptr<const linphone::ConferenceInfo> & conferenceInfo, const std::shared_ptr<const linphone::Address> & participant, linphone::ConferenceInfoError error);
// ---------------------------------------------------------------------------
};

View file

@ -111,6 +111,8 @@ class ColorListModel : public QAbstractListModel {
ADD_COLOR("event_neutral", "#424242", "Event colors that are neutral")
ADD_COLOR("event_in", "#96C11F", "Event colors that are incoming")
ADD_COLOR("event_out", "#18A7AF", "Event colors that are outgoing")
ADD_COLOR("conference_bg", "#D0D8DE", "Conferences : Background entry")
// Standard actions
//

View file

@ -38,6 +38,17 @@ ParticipantDeviceListModel::ParticipantDeviceListModel (std::shared_ptr<linphone
}
}
ParticipantDeviceListModel::ParticipantDeviceListModel (CallModel * callModel, QObject *parent) : QAbstractListModel(parent) {
if(callModel->isConference()) {
std::list<std::shared_ptr<linphone::ParticipantDevice>> devices = callModel->getConferenceModel()->getConference()->getParticipantDeviceList();
for(auto device : devices){
auto deviceModel = std::make_shared<ParticipantDeviceModel>(device);
connect(this, &ParticipantDeviceListModel::securityLevelChanged, deviceModel.get(), &ParticipantDeviceModel::onSecurityLevelChanged);
mList << deviceModel;
}
}
}
int ParticipantDeviceListModel::rowCount (const QModelIndex &index) const{
return mList.count();
}

View file

@ -29,6 +29,7 @@
#include <QString>
#include <QAbstractListModel>
class CallModel;
class ParticipantDeviceModel;
class ParticipantDeviceListModel : public QAbstractListModel {
@ -36,6 +37,7 @@ class ParticipantDeviceListModel : public QAbstractListModel {
public:
ParticipantDeviceListModel (std::shared_ptr<linphone::Participant> participant, QObject *parent = nullptr);
ParticipantDeviceListModel (CallModel * callModel, QObject *parent = nullptr);
int rowCount (const QModelIndex &index = QModelIndex()) const override;
int count();

View file

@ -51,7 +51,15 @@ bool ParticipantDeviceProxyModel::lessThan (const QModelIndex &left, const QMode
return deviceA->getTimeOfJoining() > deviceB->getTimeOfJoining();
}
//---------------------------------------------------------------------------------
CallModel * ParticipantDeviceProxyModel::getCallModel() const{
return mCallModel;
}
void ParticipantDeviceProxyModel::setCallModel(CallModel * callModel){
mCallModel = callModel;
setSourceModel(new ParticipantDeviceListModel(mCallModel));
}
void ParticipantDeviceProxyModel::setParticipant(ParticipantModel * participant){
setSourceModel(participant->getParticipantDevices().get());
}

View file

@ -31,20 +31,29 @@
class ParticipantDeviceListModel;
class ParticipantModel;
class CallModel;
class ParticipantDeviceProxyModel : public QSortFilterProxyModel {
Q_OBJECT
public:
Q_PROPERTY(CallModel * callModel READ getCallModel WRITE setCallModel NOTIFY callModelChanged)
ParticipantDeviceProxyModel (QObject *parent = nullptr);
CallModel * getCallModel() const;
void setCallModel(CallModel * callModel);
void setParticipant(ParticipantModel * participant);
signals:
void callModelChanged();
protected:
virtual bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override;
virtual bool lessThan (const QModelIndex &left, const QModelIndex &right) const override;
std::shared_ptr<ParticipantDeviceListModel> mDevices;
CallModel * mCallModel;
};

View file

@ -70,6 +70,14 @@ int ParticipantListModel::getCount() const{
return mParticipants.size();
}
std::list<std::shared_ptr<linphone::Address>> ParticipantListModel::getParticipants()const{
std::list<std::shared_ptr<linphone::Address>> participants;
for(auto participant : mParticipants){
participants.push_back(Utils::interpretUrl(participant->getSipAddress()));
}
return participants;
}
QString ParticipantListModel::addressesToString()const{
QStringList txt;
for(auto participant : mParticipants){

View file

@ -56,6 +56,7 @@ public:
Q_INVOKABLE void remove (ParticipantModel *importer);
Q_INVOKABLE ChatRoomModel* getChatRoomModel() const;
int getCount() const;
std::list<std::shared_ptr<linphone::Address>> getParticipants()const;
Q_INVOKABLE QString addressesToString()const;
Q_INVOKABLE QString displayNamesToString()const;

View file

@ -45,6 +45,10 @@ ChatRoomModel *ParticipantProxyModel::getChatRoomModel() const{
return mChatRoomModel;
}
ParticipantListModel * ParticipantProxyModel::getParticipantListModel() const{
return dynamic_cast<ParticipantListModel*>(sourceModel());
}
QStringList ParticipantProxyModel::getSipAddresses() const{
QStringList participants;
ParticipantListModel * list = dynamic_cast<ParticipantListModel*>(sourceModel());
@ -77,10 +81,12 @@ void ParticipantProxyModel::setChatRoomModel(ChatRoomModel * chatRoomModel){
if(mChatRoomModel) {
auto participants = mChatRoomModel->getParticipants();
setSourceModel(participants);
emit participantListModelChanged();
for(int i = 0 ; i < participants->getCount() ; ++i)
emit addressAdded(participants->getAt(i)->getSipAddress());
}else {
setSourceModel(new ParticipantListModel(nullptr, this));
emit participantListModelChanged();
}
sort(0);
emit chatRoomModelChanged();

View file

@ -40,6 +40,7 @@ public:
ParticipantProxyModel ( QObject *parent = Q_NULLPTR);
Q_PROPERTY(ChatRoomModel* chatRoomModel READ getChatRoomModel WRITE setChatRoomModel NOTIFY chatRoomModelChanged)
Q_PROPERTY(ParticipantListModel * participantListModel READ getParticipantListModel NOTIFY participantListModelChanged)
Q_PROPERTY(int count READ getCount NOTIFY countChanged)
Q_PROPERTY(bool showMe READ getShowMe WRITE setShowMe NOTIFY showMeChanged)
@ -47,6 +48,7 @@ public:
bool lessThan (const QModelIndex &left, const QModelIndex &right) const override;
ChatRoomModel *getChatRoomModel() const;
ParticipantListModel * getParticipantListModel() const;
Q_INVOKABLE QStringList getSipAddresses() const;
Q_INVOKABLE QVariantList getParticipants() const;
Q_INVOKABLE int getCount() const;
@ -62,6 +64,7 @@ public:
signals:
void chatRoomModelChanged();
void participantListModelChanged();
void countChanged();
void showMeChanged();
void addressAdded(QString sipAddress);

View file

@ -152,7 +152,26 @@ std::shared_ptr<TimelineModel> TimelineListModel::getTimeline(std::shared_ptr<li
}
return nullptr;
}
/*
std::shared_ptr<TimelineModel> TimelineListModel::getTimeline(std::shared_ptr<linphone::Conference> conference, const bool &create){
if(chatRoom){
for(auto it = mTimelines.begin() ; it != mTimelines.end() ; ++it){
if( (*it)->isConference() && (*it)->getConferenceModel()->getConference() == conference){
return *it;
}
}
if(create){
std::shared_ptr<TimelineModel> model = TimelineModel::create(conference);
//std::shared_ptr<TimelineModel> model = std::make_shared<TimelineModel>(chatRoom);
connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(onSelectedHasChanged(bool)));
//connect(model->getConferenceModel(), &ChatRoomModel::allEntriesRemoved, this, &TimelineListModel::removeChatRoomModel);
add(model);
return model;
}
}
return nullptr;
}
*/
QVariantList TimelineListModel::getLastChatRooms(const int& maxCount) const{
QVariantList contacts;
QMultiMap<qint64, ChatRoomModel*> sortedData;

View file

@ -40,6 +40,7 @@ public:
void selectAll(const bool& selected);
TimelineModel * getAt(const int& index);
std::shared_ptr<TimelineModel> getTimeline(std::shared_ptr<linphone::ChatRoom> chatRoom, const bool &create);
//std::shared_ptr<TimelineModel> getTimeline(std::shared_ptr<linphone::Conference> chatRoom, const bool &create);
Q_INVOKABLE QVariantList getLastChatRooms(const int& maxCount) const;
std::shared_ptr<ChatRoomModel> getChatRoomModel(std::shared_ptr<linphone::ChatRoom> chatRoom, const bool &create);
std::shared_ptr<ChatRoomModel> getChatRoomModel(ChatRoomModel * chatRoom);

View file

@ -68,7 +68,8 @@ public:
static constexpr char LinphoneBZip2_dll[] = "https://www.linphone.org/releases/windows/tools/bzip2/bzip2.dll";
static constexpr char DefaultRlsUri[] = "sips:rls@sip.linphone.org";
static constexpr char DefaultLogsEmail[] = "linphone-desktop@belledonne-communications.com";
static constexpr char DefaultConferenceURI[] = "sip:conference-factory@sip.linphone.org";
//static constexpr char DefaultConferenceURI[] = "sip:conference-factory@sip.linphone.org";
static constexpr char DefaultConferenceURI[] = "sip:videoconference-factory2@sip.linphone.org";
static constexpr char DefaultLimeServerURL[] = "https://lime.linphone.org/lime-server/lime-server.php";
static constexpr char RemoteProvisioningURL[] = "https://subscribe.linphone.org/flexiapi/provisioning";

View file

@ -70,6 +70,10 @@ bool Utils::hasCapability(const QString& address, const LinphoneEnums::FriendCap
return false;
}
QDateTime Utils::addMinutes(QDateTime date, const int& min){
return date.addSecs(min*60);
}
QString Utils::toDateTimeString(QDateTime date){
if(date.date() == QDate::currentDate())
return toTimeString(date);

View file

@ -53,6 +53,7 @@ public:
Utils(QObject * parent = nullptr) : QObject(parent){}
// Qt interfaces
Q_INVOKABLE static bool hasCapability(const QString& address, const LinphoneEnums::FriendCapability& capability);
Q_INVOKABLE static QDateTime addMinutes(QDateTime date, const int& min);
Q_INVOKABLE static QString toDateTimeString(QDateTime date);
Q_INVOKABLE static QString toTimeString(QDateTime date);
Q_INVOKABLE static QString toDateString(QDateTime date);

View file

@ -14,8 +14,9 @@ Rectangle {
property alias buttons: buttons.data // Optionnal.
property alias title : titleBar.text //Optionnal. Show a title bar with a close button.
property alias descriptionText: description.text // Optionnal.
property int buttonsAlignment : Qt.AlignLeft
property int buttonsAlignment : Qt.AlignLeft
property bool flat : false // Remove margins
property bool expandHeight: flat
property alias showCloseCross : titleBar.showCloseCross
property int buttonsLeftMargin :(buttonsAlignment & Qt.AlignLeft )== Qt.AlignLeft
@ -86,7 +87,7 @@ Rectangle {
Item {
id: content
Layout.fillHeight: (flat ? true : !dialog.contentIsEmpty)
Layout.fillHeight: (expandHeight ? true : !dialog.contentIsEmpty)
Layout.fillWidth: true
Layout.leftMargin: (flat ? 0 : DialogStyle.content.leftMargin)
Layout.rightMargin: (flat ? 0 : DialogStyle.content.rightMargin)

View file

@ -11,26 +11,29 @@ import Common 1.0
Item {
id: wrappedButton
property color defaultBackgroundColor: 'white'
property color defaultForegroundColor: 'black'
// ---------------------------------------------------------------------------
readonly property QtObject defaultColorSet : QtObject {
property int iconSize: 30
property string icon : ''
property color backgroundNormalColor : "white"
property color backgroundDisabledColor : "white"
property color backgroundHoveredColor : "white"
property color backgroundUpdatingColor : "white"
property color backgroundPressedColor : "white"
property color backgroundNormalColor : defaultBackgroundColor
property color backgroundDisabledColor : defaultBackgroundColor
property color backgroundHoveredColor : defaultBackgroundColor
property color backgroundUpdatingColor : defaultBackgroundColor
property color backgroundPressedColor : defaultBackgroundColor
// Color for shown part
property color foregroundNormalColor : "black"
property color foregroundDisabledColor : "black"
property color foregroundHoveredColor : "black"
property color foregroundUpdatingColor : "black"
property color foregroundPressedColor : "black"
property color foregroundNormalColor : defaultForegroundColor
property color foregroundDisabledColor : defaultForegroundColor
property color foregroundHoveredColor : defaultForegroundColor
property color foregroundUpdatingColor : defaultForegroundColor
property color foregroundPressedColor : defaultForegroundColor
}
property QtObject colorSet: defaultColorSet
onColorSetChanged: if(!colorSet) colorSet = defaultColorSet
property bool isCustom : false
property bool iconIsCustom: isCustom
property bool enabled: true
property bool updating: false
property bool useStates: true
@ -253,14 +256,21 @@ Item {
)
iconHeight: wrappedButton.iconHeight
iconWidth: wrappedButton.iconWidth
visible: !isCustom
visible: !iconIsCustom
}
OpacityMask{
anchors.fill: foregroundColor
source: foregroundColor
maskSource: icon
visible: isCustom
visible: iconIsCustom
MouseArea{
anchors.fill:parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
OpacityMask{
@ -268,21 +278,34 @@ Item {
anchors.fill: foregroundHiddenPartColor
source: foregroundHiddenPartColor
maskSource: icon
visible: isCustom && percentageDisplayed != 100
}
MouseArea{
anchors.fill:parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
visible: iconIsCustom && percentageDisplayed != 100
/*
layer {
enabled: true
effect: ColorOverlay {
color: "#80FFFFFF"
}
}*/
MouseArea{
anchors.fill:parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
TooltipArea {
id:tooltip
text: ''
visible:text!=''
}
MouseArea{
anchors.fill:parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
visible: !iconIsCustom
}
}
}

View file

@ -6,42 +6,50 @@ import Common.Styles 1.0
// =============================================================================
Flickable {
property alias text: textArea.text
readonly property alias length: textArea.length
boundsBehavior: Flickable.StopAtBounds
height: TextAreaFieldStyle.background.height
width: TextAreaFieldStyle.background.width
ScrollBar.vertical: ForceScrollBar {
id: scrollBar
}
TextArea.flickable: TextArea {
id: textArea
background: Rectangle {
border {
color: TextAreaFieldStyle.background.border.color
width: TextAreaFieldStyle.background.border.width
}
color: textArea.readOnly
? TextAreaFieldStyle.background.color.readOnly
: TextAreaFieldStyle.background.color.normal
radius: TextAreaFieldStyle.background.radius
}
color: TextAreaFieldStyle.text.color
font.pointSize: TextAreaFieldStyle.text.pointSize
selectByMouse: true
wrapMode: TextArea.Wrap
bottomPadding: TextAreaFieldStyle.text.padding
leftPadding: TextAreaFieldStyle.text.padding
rightPadding: TextAreaFieldStyle.text.padding + Number(scrollBar.visible) * scrollBar.width
topPadding: TextAreaFieldStyle.text.padding
}
Rectangle {
property alias text: textArea.text
readonly property alias length: textArea.length
property alias boundsBehavior: flickable.boundsBehavior
height: TextAreaFieldStyle.background.height
width: TextAreaFieldStyle.background.width
border {
color: TextAreaFieldStyle.background.border.color
width: TextAreaFieldStyle.background.border.width
}
color: textArea.readOnly
? TextAreaFieldStyle.background.color.readOnly
: TextAreaFieldStyle.background.color.normal
radius: TextAreaFieldStyle.background.radius
Flickable {
id: flickable
anchors.fill: parent
boundsBehavior: Flickable.StopAtBounds
ScrollBar.vertical: ForceScrollBar {
id: scrollBar
}
TextArea.flickable: TextArea {
id: textArea
background: Item{}
color: TextAreaFieldStyle.text.color
font.pointSize: TextAreaFieldStyle.text.pointSize
selectByMouse: true
wrapMode: TextArea.Wrap
height: flickable.height
bottomPadding: TextAreaFieldStyle.text.padding
leftPadding: TextAreaFieldStyle.text.padding
rightPadding: TextAreaFieldStyle.text.padding + Number(scrollBar.visible) * scrollBar.width
topPadding: TextAreaFieldStyle.text.padding
}
}
}

View file

@ -0,0 +1,183 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.0
import Common 1.0
import Common.Styles 1.0
// =============================================================================
ColumnLayout{
id: mainLayout
property Component delegate
function appendItem(item){
grid.model.append(item)
/*
if( bottomRowList.model.count < grid.columns - 1)
bottomRowList.model.append(item)
else
while(bottomRowList.model.count > 0 && tryToAdd(bottomRowList.model.get(0))){
bottomRowList.model.remove(0,1)
}*/
}
function add(item){
if( !grid.isLayoutWillChanged() || !transitionningTimer.running)
//grid.model.append(item)
appendItem(item)
else
bufferModels.append(item)
}
function remove(index){
if(grid.model.count > index)
grid.model.remove( index, 1)
}
function get(index){
return grid.model.get(index)
}
function tryToAdd(item){
if( !grid.isLayoutWillChanged() || !transitionningTimer.running) {
appendItem(item)
return true
}else
return false
}
property int transitionCount : 0
property var bufferModels : ListModel{}
property int maxTransitionTime: 250
Timer{
id: transitionningTimer
running: false
interval: maxTransitionTime + 5
onTriggered: updateBuffers()
}
function startTransition(){
transitionningTimer.restart()
}
function updateBuffers(){
while(bufferModels.count > 0 && tryToAdd(bufferModels.get(0))){
bufferModels.remove(0,1)
}
}
GridView{
id: grid
property int itemCount: model.count ? model.count :( model.length ? model.length : 0)
property int columns: getColumnCount(itemCount)
property int rows: getRowCount(itemCount)
function getColumnCount(itemCount){
return itemCount > 0 ? Math.sqrt(itemCount-1) + 1 : 1
}
function getRowCount(itemCount){
return columns > 1 ? (itemCount-1) / columns + 1 : 1
}
cellWidth: (mainLayout.width - 5 ) / columns
cellHeight: (mainLayout.height - 5 ) / rows
function isLayoutWillChanged(){
return columns !== getColumnCount(itemCount+1) || rows !== getRowCount(itemCount+1)
}
Layout.fillHeight: true
Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter
interactive: false
model: ListModel{}
//delegate: internalComponent
delegate: Component{
Loader{
property int modelIndex: index
height: grid.cellHeight-5
width: grid.cellWidth-5
sourceComponent: mainLayout.delegate
}
}
//------------------- ANIMATIONS
property Transition defaultTransition: Transition {
SequentialAnimation {
ScriptAction {
script: {
mainLayout.startTransition()
}
}
ParallelAnimation {
NumberAnimation { properties: "x,y"; duration: mainLayout.maxTransitionTime }
}
}
}
add: Transition {
SequentialAnimation {
ScriptAction {
script: {
mainLayout.startTransition()
}
}
ParallelAnimation {
NumberAnimation { property: "opacity"; from: 0; duration: mainLayout.maxTransitionTime }
NumberAnimation { properties: "x,y"; from: 0; duration: mainLayout.maxTransitionTime; easing.type: Easing.OutBounce }
}
}
}
addDisplaced: defaultTransition
displaced: defaultTransition
move: defaultTransition
moveDisplaced: defaultTransition
remove: Transition {
SequentialAnimation {
ScriptAction {
script: {
mainLayout.startTransition()
}
}
ParallelAnimation {
NumberAnimation { property: "opacity"; to: 0; duration: mainLayout.maxTransitionTime }
NumberAnimation { properties: "x,y"; to: 0; duration: mainLayout.maxTransitionTime }
}
}
}
removeDisplaced: defaultTransition
populate:defaultTransition
}
/*
ListView{
id: bottomRowList
Layout.preferredWidth: grid.cellWidth * model.count
Layout.preferredHeight: grid.cellHeight
Layout.alignment: Qt.AlignCenter
orientation: Qt.Horizontal
model: ListModel{}
delegate: Component{
Loader{
property int modelIndex: index
height: grid.cellHeight - 5
width: grid.cellWidth - 5
sourceComponent: mainLayout.delegate
}
}*/
/*
delegate:Rectangle{
width: grid.cellWidth
height: grid.cellHeight
onWidthChanged: console.log(width)
onHeightChanged: console.log(height)
color: '#'+ Math.floor(Math.random()*255).toString(16)
+Math.floor(Math.random()*255).toString(16)
+Math.floor(Math.random()*255).toString(16)
}*/
//}
}

View file

@ -258,6 +258,7 @@ Item {
height: parent.height
visible: _isVisible(Qt.LeftEdge)
onVisibleChanged: console.log(visible)
}
MouseArea {

View file

@ -0,0 +1,142 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import Common 1.0
import Common.Styles 1.0
import Units 1.0
Item{
id: mainItem
property alias selectedDate: monthList.selectedDate
signal clicked(date date);
RowLayout {
id: headerRow
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: 30
ActionButton{
isCustom: true
colorSet: DatePickerStyle.nextMonthButton
rotation: 180
onClicked: --monthList.currentIndex
}
Text { // month year
Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter
horizontalAlignment: Qt.AlignCenter
text: new Date(monthList.currentYear, monthList.currentMonth, 1).toLocaleString(Qt.locale(), 'MMMM yyyy')
font.pointSize: Units.dp * 11
}
ActionButton{
isCustom: true
colorSet: DatePickerStyle.nextMonthButton
onClicked: ++monthList.currentIndex
}
}
ListView {
id: monthList
anchors.top: headerRow.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
//Layout.fillWidth: true
//Layout.fillHeight: true
property int maxYears: 5 // Max years to be requested.
function set(date) {
selectedDate = new Date(date)
positionViewAtIndex((selectedDate.getFullYear()-minYear) * 12 + selectedDate.getMonth(), ListView.Center)
}
property date selectedDate
property int minYear: new Date(0,0,0).getFullYear()
snapMode: ListView.SnapOneItem
orientation: Qt.Horizontal
clip: true
// One model per month
model: (new Date().getFullYear()- minYear + maxYears) * 12
property int currentYear: Math.floor(currentIndex / 12) + minYear
property int currentMonth: currentIndex % 12
highlightFollowsCurrentItem: true
highlightRangeMode: ListView.StrictlyEnforceRange
highlightMoveDuration: 100
delegate: Item {
width: monthList.width; height: monthList.height
property int year: Math.floor(index / 12) + monthList.minYear
property int month: index % 12
property int firstDay: new Date(year, month, 1).getDay()
Column {
Grid { // 1 month calender
id: grid
width: monthList.width; height: monthList.height
property real cellWidth: width / columns;
property real cellHeight: height / rows // width and height of each cell in the grid.
columns: 7 // days
rows: 7
Repeater {
model: grid.columns * grid.rows // 49 cells per month
delegate: Rectangle { // index is 0 to 48
property int day: index - 7 // 0 = top left below Sunday (-7 to 41)
property int date: day - firstDay + 1 // 1-31
width: grid.cellWidth; height: grid.cellHeight
border.width: 0.3 * radius
border.color: new Date(year, month, date).toDateString() == monthList.selectedDate.toDateString() && text.text && day >= 0?
'black': 'transparent' // selected
radius: 0.02 * monthList.height
opacity: !mouseArea.pressed? 1: 0.3 // pressed state
Text {
id: text
anchors.centerIn: parent
font.pixelSize: day < 0 ? Units.dp * 11 : Units.dp * 10
font.bold: day < 0 || new Date(year, month, date).toDateString() == new Date().toDateString() // today
text: {
if(day < 0)
// Magic date to set day names in this order : 'S', 'M', 'T', 'W', 'T', 'F', 'S' in Locale
return new Date(1,3,index).toLocaleString(Qt.locale(), 'ddd')[0]
else if(new Date(year, month, date).getMonth() == month)
return date
else
return ''
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
enabled: text.text && day >= 0
onClicked: {
monthList.selectedDate = new Date(year, month, date)
mainItem.clicked(monthList.selectedDate)
}
}
}
}
}
}
}
Component.onCompleted: set(mainItem.selectedDate)
}
}

View file

@ -0,0 +1,170 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import Common 1.0
import Common.Styles 1.0
import Units 1.0
Item{
id: mainItem
property date selectedTime
property int border: 25
property int centerPosition: Math.min(height, width)/2
property int middleMinSize: centerPosition - border // Minus border
signal clicked(date date)
PathView {
id: outer
model: 24
interactive: false
highlightRangeMode: PathView.NoHighlightRange
highlight: Rectangle {
id: rect
width: 30 * 1.5
height: width
radius: width / 2
border.color: "darkgray"
color: TimePickerStyle.hoursColor
}
delegate: Item {
id: del
width: 30
height: 30
property bool currentItem: PathView.view.currentIndex == index
property alias text : hourText.text
Text {
id: hourText
anchors.centerIn: parent
font.pointSize: Units.dp * 11
font.bold: currentItem
text: index
color: currentItem ? TimePickerStyle.selectedItemColor : TimePickerStyle.unselectedItemColor
}
MouseArea {
anchors.fill: parent
onClicked: outer.currentIndex = index
}
}
path: Path {
id: outPath
//property int xStep: middleMinSize * Math.sin(2 * Math.PI / outer.count)
property int yStep: middleMinSize * Math.cos(2 * Math.PI / outer.count)
//startX: xStep + mainItem.width/2; startY: yStep + mainItem.height/2
startX: mainItem.centerPosition
startY: mainItem.centerPosition - outPath.yStep
PathArc {
x: mainItem.centerPosition; y: mainItem.centerPosition + outPath.yStep
radiusX: 110; radiusY: 110
useLargeArc: false
}
PathArc {
x: mainItem.centerPosition; y: mainItem.centerPosition - outPath.yStep
radiusX: 110; radiusY: 110
useLargeArc: false
}
}
}
PathView {
id: inner
model: 6
interactive: false
highlightRangeMode: PathView.NoHighlightRange
highlight: Rectangle {
width: 30 * 1.5
height: width
radius: width / 2
border.color: "darkgray"
color: TimePickerStyle.minutesColor
}
delegate: Item {
width: 30
height: 30
property bool currentItem: PathView.view.currentIndex == index
property alias text : textMin.text
Text {
id: textMin
anchors.centerIn: parent
font.pointSize: Units.dp * 11
font.bold: currentItem
text: index * 10
color: currentItem ? TimePickerStyle.selectedItemColor : TimePickerStyle.unselectedItemColor
}
MouseArea {
anchors.fill: parent
onClicked: inner.currentIndex = index
}
}
path: Path {
id: innerPath
//property int xStep: middleMinSize * Math.sin(2 * Math.PI / inner.count)
property int yStep: middleMinSize * Math.cos(2 * Math.PI / inner.count)
startX: mainItem.centerPosition; startY: mainItem.centerPosition - innerPath.yStep
PathArc {
x: mainItem.centerPosition; y: mainItem.centerPosition + innerPath.yStep
radiusX: 40; radiusY: 40
useLargeArc: false
}
PathArc {
x: mainItem.centerPosition; y: mainItem.centerPosition - innerPath.yStep
radiusX: 40; radiusY: 40
useLargeArc: false
}
}
}
RowLayout {
id: selectedTimeArea
x: centerPosition - width/2
y: centerPosition - height/2
Text {
id: h
font.pointSize: Units.dp * 12
font.bold: true
text: outer.currentItem.text.length < 2 ? '0' + outer.currentItem.text : outer.currentItem.text
}
Text {
id: div
font.pointSize: Units.dp * 12
font.bold: true
text: ':'
}
Text {
id: m
font.pointSize: Units.dp * 12
font.bold: true
text: inner.currentItem.text.length < 2 ? '0' + inner.currentItem.text : inner.currentItem.text
}
}
MouseArea {
anchors.fill: selectedTimeArea
onClicked: {
var d = new Date()
d.setHours(outer.currentItem.text)
d.setMinutes(inner.currentItem.text)
mainItem.clicked(d)
}
}
Component.onCompleted: {
outer.currentIndex = mainItem.selectedTime.getHours() % 24
inner.currentIndex = mainItem.selectedTime.getMinutes() / 10
}
}

View file

@ -0,0 +1,23 @@
pragma Singleton
import QtQml 2.2
import Units 1.0
import ColorsList 1.0
// =============================================================================
QtObject {
property string sectionName : 'DatePicker'
property QtObject nextMonthButton: QtObject {
property int iconSize: 20
property string name : 'nextMonth'
property string icon : 'panel_arrow_custom'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_b_n', icon, 'l_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_b_h', icon, 'l_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_b_p', icon, 'l_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_f_n', icon, 'l_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_f_h', icon, 'l_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_f_p', icon, 'l_p_b_fg').color
}
}

View file

@ -0,0 +1,16 @@
pragma Singleton
import QtQml 2.2
import Units 1.0
import ColorsList 1.0
// =============================================================================
QtObject {
property string sectionName : 'TimePicker'
property color hoursColor: ColorsList.add(sectionName+'_hours', 'i').color
property color minutesColor: ColorsList.add(sectionName+'_minutes', 's').color
property color selectedItemColor: ColorsList.add(sectionName+'_selected', 'l').color
property color unselectedItemColor: ColorsList.add(sectionName+'_unselected', 'g').color
}

View file

@ -52,6 +52,9 @@ singleton MenuStyle 1.0 Menus/MenuStyle.qml
singleton ForceScrollBarStyle 1.0 Misc/ForceScrollBarStyle.qml
singleton PanedStyle 1.0 Misc/PanedStyle.qml
singleton DatePickerStyle 1.0 Picker/DatePickerStyle.qml
singleton TimePickerStyle 1.0 Picker/TimePickerStyle.qml
singleton PopupStyle 1.0 Popup/PopupStyle.qml
singleton TooltipStyle 1.0 Tooltip/TooltipStyle.qml

View file

@ -25,6 +25,7 @@ CommonItemDelegate 1.0 Form/CommonItemDelegate.qml
DroppableTextArea 1.0 Form/DroppableTextArea.qml
ListForm 1.0 Form/ListForm.qml
ListItemSelector 1.0 Form/ListItemSelector.qml
Mosaic 1.0 Form/Mosaic.qml
MouseArea 1.0 Form/MouseArea.qml
SearchBox 1.0 Form/SearchBox.qml
Slider 1.0 Form/Slider.qml
@ -80,6 +81,9 @@ Borders 1.0 Misc/Borders.qml
ForceScrollBar 1.0 Misc/ForceScrollBar.qml
Paned 1.0 Misc/Paned.qml
DatePicker 1.0 Picker/DatePicker.qml
TimePicker 1.0 Picker/TimePicker.qml
DesktopPopup 1.0 Popup/DesktopPopup.qml
Popup 1.0 Popup/Popup.qml
PopupShadow 1.0 Popup/PopupShadow.qml

View file

@ -79,11 +79,12 @@ SearchBox {
}, {
colorSet: SettingsModel.getShowStartChatButton() ? SipAddressesViewStyle.chat : SipAddressesViewStyle.history,
secure: 0,
visible: SettingsModel.standardChatEnabled ,
handler: function (entry) {
searchBox.closeMenu()
searchBox.launchChat(entry.sipAddress)
}
},
visible: SettingsModel.standardChatEnabled,
zz: 'toto'
}, {
colorSet: SettingsModel.getShowStartChatButton() ? SipAddressesViewStyle.chat : SipAddressesViewStyle.history,
secure: 1,

View file

@ -124,14 +124,15 @@ ScrollableListView {
visible: modelData.visible
onClicked: sipAddressesView.actions[index].handler({ // Do not use modelData on functions : Qt bug
onClicked: {
sipAddressesView.actions[index].handler({ // Do not use modelData on functions : Qt bug
sipAddress: sipAddressesView.interpretableSipAddress
})
}
Icon{
visible: modelData.secure>0 &&
// Do not use modelData on functions : Qt bug
visible: modelData.secure>0 &&
// Do not use modelData on functions : Qt bug
(sipAddressesView.actions[index].secureIconVisibleHandler ? sipAddressesView.actions[index].secureIconVisibleHandler({ sipAddress : sipAddressesView.interpretableSipAddress}) : true)
icon: 'secure_on'
iconSize: parent.height/2
anchors.top:parent.top
@ -295,13 +296,11 @@ ScrollableListView {
visible: modelData.visible
onClicked: {// Do not use modelData on functions : Qt bug
sipAddressesView.actions[index].handler(sipAddressEntry.entry)
}
Icon{
visible: modelData.secure>0 &&
// Do not use modelData on functions : Qt bug
(sipAddressesView.actions[index].secureIconVisibleHandler ? sipAddressesView.actions[index].secureIconVisibleHandler(sipAddressEntry.entry) : true)
icon: 'secure_on'
iconSize: parent.height/2
anchors.top:parent.top

View file

@ -63,7 +63,8 @@ function openConferenceManager (params, exitHandler) {
function getContent () {
var call = window.call
if (call == null) {
return conference
//return conference
return videoConference
}
var status = call.status
@ -83,7 +84,8 @@ function getContent () {
if (status === CallModel.CallStatusEnded) {
return endedCall
}
if(call.isConference)
return videoConference
return incall
}

View file

@ -34,6 +34,9 @@ Window {
// ---------------------------------------------------------------------------
function openConference(){
middlePane.sourceComponent = videoConference
}
function openChat () {
rightPaned.open()
@ -43,7 +46,6 @@ Window {
rightPaned.close()
}
function conferenceManagerResult(exitValue){
window.detachVirtualWindow();
if(exitValue == 0 && calls.count == 0)
@ -146,7 +148,7 @@ Window {
Layout.fillHeight: true
Layout.fillWidth: true
conferenceModel: ConferenceModel {}
conferenceModel: ConferenceProxyModel {}
model: CallsListProxyModel {}
}
}
@ -234,12 +236,20 @@ Window {
}
}
Component {
id: videoConference
VideoConference {
callModel: window.call
}
}
// -----------------------------------------------------------------------
childA: Loader {
id: middlePane
anchors.fill: parent
sourceComponent: Logic.getContent()
onSourceComponentChanged: {rightPaned.childAItem.update()}// Force update when loading a new Content. It's just to be sure
onSourceComponentChanged: {console.log(sourceComponent); rightPaned.childAItem.update()}// Force update when loading a new Content. It's just to be sure
}
childB: Loader {

View file

@ -0,0 +1,370 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import Common 1.0
import Common.Styles 1.0
import Linphone 1.0
import LinphoneUtils 1.0
import UtilsCpp 1.0
import App.Styles 1.0
// =============================================================================
Rectangle {
id: conference
property CallModel callModel
// ---------------------------------------------------------------------------
color: VideoConferenceStyle.backgroundColor
Component.onCompleted: {
for(var i = 0 ; i < 5 ; ++i)
grid.add({color: '#'+ Math.floor(Math.random()*255).toString(16)
+Math.floor(Math.random()*255).toString(16)
+Math.floor(Math.random()*255).toString(16)})
}
// ---------------------------------------------------------------------------
ColumnLayout {
anchors.fill: parent
spacing: 0
// -------------------------------------------------------------------------
// Conference info.
// -------------------------------------------------------------------------
RowLayout{
// Aux features
Layout.topMargin: 10
Layout.leftMargin: 25
Layout.rightMargin: 25
spacing: 10
ActionButton{
isCustom: true
backgroundRadius: width/2
colorSet: VideoConferenceStyle.buttons.callsList
}
ActionButton{
isCustom: true
backgroundRadius: width/2
colorSet: VideoConferenceStyle.buttons.dialpad
}
// Title
Text{
horizontalAlignment: Qt.AlignHCenter
Layout.fillWidth: true
text: 'Sujet de la conférence' + ' - ' + '02:23:12'
color: VideoConferenceStyle.title.color
font.pointSize: VideoConferenceStyle.title.pointSize
}
// Mode buttons
ActionButton{
isCustom: true
backgroundRadius: width/2
colorSet: VideoConferenceStyle.buttons.screenSharing
}
ActionButton{
isCustom: true
backgroundRadius: width/2
colorSet: VideoConferenceStyle.buttons.recordOff
}
ActionButton{
isCustom: true
backgroundRadius: width/2
colorSet: VideoConferenceStyle.buttons.screenshot
}
ActionButton{
isCustom: true
backgroundRadius: width/2
colorSet: VideoConferenceStyle.buttons.fullscreen
}
}
// -------------------------------------------------------------------------
// Contacts visual.
// -------------------------------------------------------------------------
MouseArea{
id: mainGrid
Layout.fillHeight: true
Layout.fillWidth: true
Layout.leftMargin: 70
Layout.rightMargin: 70
Layout.topMargin: 15
Layout.bottomMargin: 20
onClicked: {
grid.add({color: '#'+ Math.floor(Math.random()*255).toString(16)
+Math.floor(Math.random()*255).toString(16)
+Math.floor(Math.random()*255).toString(16)})
}
/*
ParticipantDeviceProxyModel{
id: participantDevices
callModel: conference.callModel
}*/
Mosaic {
id: grid
anchors.fill: parent
property int radius : 8
delegate:
Rectangle{
color: grid.get(modelIndex) && grid.get(modelIndex).color ? grid.get(modelIndex).color : '' // modelIndex is a custom index because by Mosaic modelisation, it is not accessible.
radius: grid.radius
/*
Item {
id: container
Layout.fillWidth: true
Layout.fillHeight: true
Layout.margins: CallStyle.container.margins
Component {
id: avatar
IncallAvatar {
call: grid.get(modelIndex).call
height: Logic.computeAvatarSize(CallStyle.container.avatar.maxSize)
width: height
}
}
Loader {
id: cameraLoader
anchors.centerIn: parent
active: incall.call.videoEnabled && !_fullscreen
sourceComponent: camera
Component {
id: camera
Camera {
call: grid.get(modelIndex).call
height: container.height
width: container.width
}
}
}
Loader {
anchors.centerIn: parent
active: !grid.get(modelIndex).call.videoEnabled || _fullscreen
sourceComponent: avatar
}
}*/
MouseArea{
anchors.fill: parent
onClicked: {grid.remove( modelIndex)}
}
}
}
}
/*
GridLayout {
id: grid
Layout.fillHeight: true
Layout.fillWidth: true
Layout.leftMargin: 70
Layout.rightMargin: 70
Layout.topMargin: 15
Layout.bottomMargin: 20
Layout.alignment: Qt.AlignCenter
columns: 3
property int radius : 8
Rectangle{
Layout.fillHeight: true
Layout.fillWidth: true
color: 'red'
radius: parent.radius
}
Rectangle{
Layout.fillHeight: true
Layout.fillWidth: true
color: 'green'
radius: parent.radius
}
Rectangle{
Layout.fillHeight: true
Layout.fillWidth: true
color: 'orange'
radius: parent.radius
}
Rectangle{
Layout.fillHeight: true
Layout.fillWidth: true
color: 'yellow'
radius: parent.radius
}
Rectangle{
Layout.fillHeight: true
Layout.fillWidth: true
Layout.columnSpan: 2
color: 'blue'
radius: parent.radius
}
Rectangle{
Layout.fillHeight: true
Layout.fillWidth: true
color: 'pink'
radius: parent.radius
}
}
*/
// -------------------------------------------------------------------------
// Action Buttons.
// -------------------------------------------------------------------------
RowLayout{
Layout.fillWidth: true
Layout.bottomMargin: 40
Layout.leftMargin: 25
Layout.rightMargin: 25
// Security
ActionButton{
//Layout.preferredHeight: VideoConferenceStyle.buttons.buttonSize
//Layout.preferredWidth: VideoConferenceStyle.buttons.buttonSize
height: VideoConferenceStyle.buttons.secure.buttonSize
width: height
isCustom: true
iconIsCustom: false
backgroundRadius: width/2
colorSet: VideoConferenceStyle.buttons.secure
icon: 'secure_level_1'
}
Item{
Layout.fillWidth: true
}
// Action buttons
RowLayout{
Layout.alignment: Qt.AlignCenter
spacing: 10
RowLayout{
Row {
spacing: 2
VuMeter {
Timer {
interval: 50
repeat: true
}
}
ActionSwitch {
id: micro
isCustom: true
backgroundRadius: 90
colorSet: enabled ? VideoConferenceStyle.buttons.microOn : VideoConferenceStyle.buttons.microOff
}
}
Row {
spacing: 2
VuMeter {
Timer {
interval: 50
repeat: true
}
}
ActionSwitch {
id: speaker
isCustom: true
backgroundRadius: 90
colorSet: enabled ? VideoConferenceStyle.buttons.speakerOn : VideoConferenceStyle.buttons.speakerOff
}
}
ActionSwitch {
id: camera
isCustom: true
backgroundRadius: 90
colorSet: enabled ? VideoConferenceStyle.buttons.cameraOn : VideoConferenceStyle.buttons.cameraOff
}
}
RowLayout{
ActionButton{
isCustom: true
backgroundRadius: width/2
colorSet: VideoConferenceStyle.buttons.pause
}
ActionButton{
isCustom: true
backgroundRadius: width/2
colorSet: VideoConferenceStyle.buttons.hangup
}
}
}
Item{
Layout.fillWidth: true
}
// Panel buttons
RowLayout{
ActionButton{
isCustom: true
backgroundRadius: width/2
colorSet: VideoConferenceStyle.buttons.chat
}
ActionButton{
isCustom: true
backgroundRadius: width/2
colorSet: VideoConferenceStyle.buttons.participants
}
ActionButton {
id: callQuality
isCustom: true
backgroundRadius: 4
colorSet: VideoConferenceStyle.buttons.callQuality
percentageDisplayed: 0
//onClicked: Logic.openCallStatistics()
// See: http://www.linphone.org/docs/liblinphone/group__call__misc.html#ga62c7d3d08531b0cc634b797e273a0a73
Timer {
interval: 500
repeat: true
running: true
triggeredOnStart: true
onTriggered: {
callQuality.percentageDisplayed = (callQuality.percentageDisplayed + 10 ) % 110
/*
// Note: `quality` is in the [0, 5] interval and -1.
var quality = call.quality
if(quality >= 0)
callQuality.percentageDisplayed = quality * 100 / 5
else
callQuality.percentageDisplayed = 0
*/
}
}
/*
CallStatistics {
id: callStatistics
call: incall.call
width: container.width
relativeTo: callQuality
relativeY: CallStyle.header.stats.relativeY
onClosed: Logic.handleCallStatisticsClosed()
}*/
}
ActionButton{
isCustom: true
backgroundRadius: width/2
colorSet: VideoConferenceStyle.buttons.options
}
}
}
}
}

View file

@ -0,0 +1,234 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import Common 1.0
import Linphone 1.0
import Utils 1.0
import UtilsCpp 1.0
import LinphoneEnums 1.0
import App.Styles 1.0
// =============================================================================
ColumnLayout {
id: container
spacing: 0
// ---------------------------------------------------------------------------
// Title
// ---------------------------------------------------------------------------
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: ConferencesStyle.bar.height
color: ConferencesStyle.bar.backgroundColor
Text{
anchors.verticalCenter: parent.center
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 40
text: 'Mes conférences'
}
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: ConferencesStyle.bar.height
color: 'white'
RowLayout {
anchors {
fill: parent
leftMargin: ConferencesStyle.bar.leftMargin
rightMargin: ConferencesStyle.bar.rightMargin
}
spacing: ConferencesStyle.spacing
ExclusiveButtons {
texts: [
'TERMINEES',
'PROGRAMMEES',
'INVITATIONS'
]
}
}
}
// ---------------------------------------------------------------------------
// Conferences list.
// ---------------------------------------------------------------------------
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: ConferencesStyle.backgroundColor
ScrollableListView {
anchors.fill: parent
spacing: 10
highlightFollowsCurrentItem: false
section {
criteria: ViewSection.FullString
delegate: sectionHeading
property: 'dateTime'
}
model: ConferenceInfoProxyModel{}
/* ListModel{
ListElement{date: '2020/12/01'; time: '10:00:00';duration: 60;organizerName: 'Dupont';subject:'Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam' }
ListElement{date: '2020/12/01'; time: '14:00:00';duration: 30;organizerName: 'Moi';subject:'TOTO';participantes: 'Julien' }
ListElement{date: '2020/12/01'; time: '10:10:00';duration: 120;organizerName: 'Henri';subject:'Eskimirbief, mais ou est donc Willy?';participantes: 'Julien'}
ListElement{date: '2020/12/04'; time: '09:00:00';duration: 300;organizerName: 'Houlahoup';subject:'Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam'}
ListElement{date: '2020/12/05'; time: '10:00:00';duration: 60;organizerName: 'Dupont';subject:'1. Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam' }
ListElement{date: '2020/12/05'; time: '10:00:00';duration: 60;organizerName: 'Dupont';subject:'2. Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam' }
ListElement{date: '2020/12/06'; time: '10:00:00';duration: 60;organizerName: 'Dupont';subject:'1. Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam' }
ListElement{date: '2020/12/06'; time: '10:00:00';duration: 60;organizerName: 'Dupont';subject:'2. Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam' }
ListElement{date: '2020/12/06'; time: '10:00:00';duration: 60;organizerName: 'Dupont';subject:'3. Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam' }
ListElement{date: '2020/12/06'; time: '10:00:00';duration: 60;organizerName: 'Dupont';subject:'4. Atelier loisir: boumbo en folie';participantes: 'Martin, Jordy, allelouilla, Artemis Gordon, jobarteam' }
}*/
// -----------------------------------------------------------------------
// Heading.
// -----------------------------------------------------------------------
Component {
id: sectionHeading
Item {
implicitHeight: container.height + ConferencesStyle.sectionHeading.bottomMargin
width: parent.width
Borders {
id: container
borderColor: ConferencesStyle.sectionHeading.border.color
bottomWidth: ConferencesStyle.sectionHeading.border.width
implicitHeight: text.contentHeight +
ConferencesStyle.sectionHeading.padding * 2 +
ConferencesStyle.sectionHeading.border.width * 2
topWidth: ConferencesStyle.sectionHeading.border.width
width: parent.width
Text {
id: text
anchors.fill: parent
color: ConferencesStyle.sectionHeading.text.color
font {
bold: true
pointSize: ConferencesStyle.sectionHeading.text.pointSize
}
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
// Cast section to integer because Qt converts the
// sectionDate in string!!!
text: new Date(section).toLocaleDateString(
Qt.locale(App.locale)
)
}
}
}
}
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
delegate: Rectangle {
id: entry
anchors {
left: parent ? parent.left : undefined
leftMargin: 0
right: parent ? parent.right : undefined
rightMargin: 0
}
radius: 6
color: ConferencesStyle.conference.backgroundColor.normal
implicitHeight: layout.height + ConferencesStyle.conference.bottomMargin
// ---------------------------------------------------------------------
MouseArea {
id: mouseArea
cursorShape: Qt.ArrowCursor
hoverEnabled: true
implicitHeight: layout.height
width: parent.width + parent.anchors.rightMargin
//acceptedButtons: Qt.NoButton
onClicked: CallsListModel.launchVideoCall(modelData.uri, '', 0)
ColumnLayout{
id: layout
spacing: 0
width: entry.width
RowLayout {
RowLayout {
id: scheduleRow
spacing: ConferencesStyle.conference.spacing
Icon{
icon: ConferencesStyle.conference.schedule.icon
iconSize: ConferencesStyle.conference.schedule.iconSize
overwriteColor: ConferencesStyle.conference.schedule.color
}
Text {
Layout.fillWidth: true
color: ConferencesStyle.conference.schedule.color
elide: Text.ElideRight
font.pointSize: ConferencesStyle.conference.schedule.pointSize
text: Qt.formatDateTime(modelData.dateTime, 'yyyy/MM/dd hh:mm')
}
}
Text{
Layout.fillWidth: true
Layout.alignment: Qt.AlignRight
color: ConferencesStyle.conference.schedule.color
font.pointSize: ConferencesStyle.conference.schedule.pointSize
text: 'Organisateur : ' +UtilsCpp.getDisplayName(modelData.organizer)
}
}
Text{
Layout.fillWidth: true
Layout.alignment: Qt.AlignRight
color: ConferencesStyle.conference.schedule.color
font.pointSize: ConferencesStyle.conference.schedule.pointSize
text: modelData.subject
}
RowLayout {
id: participantsRow
spacing: ConferencesStyle.conference.spacing
Icon{
icon: ConferencesStyle.conference.participants.icon
iconSize: ConferencesStyle.conference.participants.iconSize
overwriteColor: ConferencesStyle.conference.participants.color
}
Text {
Layout.fillWidth: true
color: ConferencesStyle.conference.participants.color
elide: Text.ElideRight
font.pointSize: ConferencesStyle.conference.participants.pointSize
text: modelData.displayNamesToString
}
}
}
}
}
}
}
}

View file

@ -0,0 +1,530 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.3
import Common 1.0
import Linphone 1.0
//import LinphoneUtils 1.0
import LinphoneEnums 1.0
import App.Styles 1.0
import Common.Styles 1.0
import Units 1.0
import UtilsCpp 1.0
import ColorsList 1.0
// =============================================================================
DialogPlus {
id: conferenceManager
property ConferenceInfoModel conferenceInfoModel: ConferenceInfoModel{}
readonly property int minParticipants: 1
buttons: [
ColumnLayout{
Layout.fillWidth: true
Layout.topMargin:15
Layout.alignment: Qt.AlignLeft
Layout.leftMargin: 15
spacing:4
Text {
Layout.fillWidth: true
//: 'Would you like to encrypt your conference?' : Ask about setting the conference as secured.
text:qsTr('askEncryption')
color: NewConferenceStyle.askEncryptionColor
font.pointSize: Units.dp * 11
font.weight: Font.DemiBold
}
Item{
Layout.fillWidth: true
Layout.preferredHeight: 50
Icon{
id:secureOff
anchors.left:parent.left
anchors.leftMargin : 0
anchors.verticalCenter: parent.verticalCenter
width:20
height:20
icon: 'secure_off'
iconSize:20
}
Switch{
id:secureSwitch
anchors.left:secureOff.right
anchors.leftMargin : 5
anchors.verticalCenter: parent.verticalCenter
width:50
enabled:true
checked: !SettingsModel.standardChatEnabled && SettingsModel.secureChatEnabled
onClicked: {
var newCheck = checked
if(SettingsModel.standardChatEnabled && checked || SettingsModel.secureChatEnabled && !checked)
newCheck = !checked;
checked = newCheck;
}
indicatorStyle: SwitchStyle.aux
}
Icon{
id:secureOn
anchors.left:secureSwitch.right
anchors.leftMargin : 15
anchors.verticalCenter: parent.verticalCenter
width:20
height:20
icon: 'secure_on'
iconSize:20
}
}
},
TextButtonA {
//: 'Cancel' : Cancel button
text: qsTr('cancelButton')
capitalization: Font.AllUppercase
onClicked: exit(0)
},
TextButtonB {
enabled: selectedParticipants.count >= conferenceManager.minParticipants && subject.text != '' && AccountSettingsModel.conferenceURI != ''
//: 'Launch' : Start button
text: qsTr('startButton')
capitalization: Font.AllUppercase
function getInviteMode(){
//return inviteAppAccountCheckBox.checked ? LinphoneEnums::
return 0;
}
onClicked: {
if( scheduledSwitch.checked){
var startDateTime = new Date()
startDateTime.setDate(Date.fromLocaleDateString(locale, dateField.text, Locale.ShortFormat))
startDateTime.setTime( Date.fromLocaleTimeString(locale, timeField.text, Locale.ShortFormat))
conferenceInfoModel.dateTime = startDateTime
}
conferenceInfoModel.subject = subject.text
conferenceInfoModel.description = description.text
conferenceInfoModel.setParticipants(selectedParticipants.participantListModel)
var callsWindow = App.getCallsWindow()
App.smartShowWindow(callsWindow)
callsWindow.openConference()
CallsListModel.createConference(conferenceInfoModel, secureSwitch.checked, getInviteMode(), false )
exit(1)
}
TooltipArea{
visible: AccountSettingsModel.conferenceURI == '' || subject.text == '' || selectedParticipants.count < conferenceManager.minParticipants
maxWidth: participantView.width
delay:0
text: {
var txt = '\n';
if( subject.text == '')
//: 'You need to fill a subject.' : Tooltip to warn a user on missing field.
txt ='- ' + qsTr('missingSubject') + '\n'
if( selectedParticipants.count < conferenceManager.minParticipants)
//: 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation.
txt += '- ' + qsTr('missingParticipants', '', conferenceManager.minParticipants).arg(conferenceManager.minParticipants) + '\n'
if( AccountSettingsModel.conferenceURI == '')
//: 'You need to set the conference URI in your account settings to create a conference based chat room.' : Tooltip to warn the user that a setting is missong in its configuration.
txt += '- ' + qsTr('missingConferenceURI') + '\n'
return txt;
}
}
}
]
buttonsAlignment: Qt.AlignRight
buttonsLeftMargin: 15
//: 'Start a video conference' : Title of a popup about creation of a video conference
title:qsTr('newConferenceTitle')
height: window.height - 100
width: window.width - 100
expandHeight: true
// ---------------------------------------------------------------------------
RowLayout {
height: parent.height
width: parent.width
spacing: 0
ColumnLayout {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.topMargin: 10
spacing: 10
ColumnLayout {
Layout.fillWidth: true
Layout.rightMargin: 15
spacing:5
Text{
textFormat: Text.RichText
//: 'Subject' : Label of a text field about the subject of the chat room
text :qsTr('subjectLabel') +'<span style="color:red">*</span>'
color: NewConferenceStyle.subjectTitleColor
font.pointSize: Units.dp * 11
font.weight: Font.DemiBold
}
TextField {
id:subject
Layout.fillWidth: true
//: 'Give a subject' : Placeholder in a form about setting a subject
placeholderText : qsTr('subjectPlaceholder')
text: conferenceInfoModel && conferenceInfoModel.subject || ''
Keys.onReturnPressed: nextItemInFocusChain().forceActiveFocus()
TooltipArea{
//: 'Current subject of the Chat Room. It cannot be empty'
//~ Tooltip Explanation about the subject of the chat room
text : qsTr('subjectTooltip')
}
}
}
Rectangle{
Layout.fillWidth: true
Layout.preferredHeight: scheduledSwitch.checked ? 120 : 50
Layout.rightMargin: 15
color: '#F7F7F7'
ColumnLayout{
anchors.fill: parent
spacing: 0
RowLayout{
Layout.fillWidth: true
Layout.preferredHeight: 50
Switch{
id:scheduledSwitch
Layout.leftMargin : 5
Layout.alignment: Qt.AlignVCenter
width:50
enabled: true
checked: true
onClicked: {
//checked = !checked
}
indicatorStyle: SwitchStyle.aux
}
Text {
Layout.fillWidth: true
Layout.rightMargin: 15
//: 'Would you like to schedule your conference?' : Ask about setting the conference as scheduled.
text: 'Souhaitez-vous programmer cette conférence pour plus tard ?'
color: NewConferenceStyle.askEncryptionColor
font.pointSize: Units.dp * 10
font.weight: Font.DemiBold
wrapMode: Text.WordWrap
}
}
GridLayout{
id: scheduleForm
visible: scheduledSwitch.checked
Layout.fillWidth: true
Layout.fillHeight: true
columns: 4
property var locale: Qt.locale()
property date currentDate: new Date()
property int cellWidth: (parent.width-15)/columns
Component.onCompleted: scheduleForm.updateDateTime()
Text{text: 'Date*'; Layout.preferredWidth: parent.cellWidth}
Text{text: 'Heure de début*'; Layout.preferredWidth: parent.cellWidth}
Text{text: 'Durée'; Layout.preferredWidth: parent.cellWidth}
Text{text: 'Fuseau horaire'; Layout.preferredWidth: parent.cellWidth}
TextField{id: dateField; Layout.preferredWidth: parent.cellWidth
function getDate(){
return Date.fromLocaleDateString(scheduleForm.locale, text,'yyyy/MM/dd')
}
function setDate(date){
text = date.toLocaleDateString(scheduleForm.locale, 'yyyy/MM/dd')
}
MouseArea{
anchors.fill: parent
onClicked: {
if( rightStackView.currentItemType === 1) {
rightStackView.currentItemType = 0
rightStackView.pop()// Cancel
}else {
if( rightStackView.depth > 1 )
rightStackView.pop()//Remove previous request
rightStackView.currentItemType = 1
rightStackView.push(datePicker, {selectedDate: new Date(dateField.getDate())})
}
}
}
}
TextField{id: timeField; Layout.preferredWidth: parent.cellWidth
function getTime(){
return Date.fromLocaleTimeString(scheduleForm.locale, timeField.text, 'hh:mm')
}
function setTime(date){
text = date.toLocaleTimeString(scheduleForm.locale, 'hh:mm')
}
MouseArea{
anchors.fill: parent
onClicked: {
if( rightStackView.currentItemType === 2) {
rightStackView.currentItemType = 0
rightStackView.pop()// Cancel
}else {
if( rightStackView.depth > 1 )
rightStackView.pop()//Remove previous request
rightStackView.currentItemType = 2
rightStackView.push(timePicker,{selectedTime: new Date(timeField.getTime())})
}
}
}
}
NumericField{ text: '1200'; readOnly: true; Layout.preferredWidth: parent.cellWidth}
TextField{ text: 'Paris'; readOnly: true; Layout.preferredWidth: parent.cellWidth}
function updateDateTime(){
var storedDate = new Date()
if( dateField.text != '' && timeField.text != ''){
storedDate.setDate(dateField.getDate())
storedDate.setTime(timeField.getTime() )
}
var currentDate = new Date()
if(currentDate >= storedDate){
var nextStoredDate = UtilsCpp.addMinutes(new Date(), 5)
dateField.setDate(nextStoredDate)
timeField.setTime(nextStoredDate)
}
}
Timer{
running: scheduleForm.visible
repeat: true
interval: 1000
onTriggered: {
scheduleForm.updateDateTime()
}
}
}
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.rightMargin: 15
spacing:5
Text{
Layout.fillWidth: true
Layout.preferredHeight: 20
textFormat: Text.RichText
//: 'Add a description' : Label of a text field about the description of the conference
text : 'Ajouter une description'
color: NewConferenceStyle.subjectTitleColor
font.pointSize: Units.dp * 10
font.weight: Font.DemiBold
}
TextAreaField {
id: description
Layout.fillWidth: true
Layout.fillHeight: true
//: 'Description' : Placeholder in a form about setting a description
//placeholderText : 'Description'
text: ''
Keys.onReturnPressed: nextItemInFocusChain().forceActiveFocus()
TooltipArea{
//: 'This description will describe the conference' : Explanation about the description of the conference
text : 'This description will describe the conference'
}
}
}
ColumnLayout{
Layout.fillWidth: true
//Layout.preferredHeight: 60
spacing: 5
CheckBoxText {
id: inviteAppAccountCheckBox
text: 'Envoyer l\'invitation via mon compte Linphone'
width: parent.width
checked: true
onClicked: {
console.log('Send invite with Linphone account: ' + checked)
}
}
CheckBoxText {
id: inviteEmailCheckBox
text: 'Envoyer l\'invitation via mon adresse mail'
width: parent.width
onClicked: {
console.log('Send invite with email: ' + checked)
}
}
}
}
StackView{
id: rightStackView
property int currentItemType: 0
Layout.fillHeight: true
Layout.fillWidth: true
Layout.minimumWidth: 200
Layout.topMargin: 10
Layout.bottomMargin: 10
clip: true
// -------------------------------------------------------------------------
// See and remove selected addresses.
// -------------------------------------------------------------------------
initialItem: ColumnLayout{
//anchors.fill: parent
Rectangle{
Layout.fillHeight: true
Layout.fillWidth: true
border.width: 1
border.color: NewConferenceStyle.addressesBorderColor
ColumnLayout {
anchors.fill: parent
anchors.topMargin: 15
anchors.leftMargin: 10
anchors.rightMargin: 10
spacing: 0
SmartSearchBar {
id: smartSearchBar
Layout.fillWidth: true
Layout.topMargin: ConferenceManagerStyle.columns.selector.spacing
showHeader:false
maxMenuHeight: MainWindowStyle.searchBox.maxHeight
//: 'Select participants' : Placeholder for a search on participant to add them in selection.
placeholderText: qsTr('participantSelectionPlaceholder')
//: 'Search in your contacts or add a custom one to the chat room.'
tooltipText: qsTr('participantSelectionTooltip')
actions:[{
colorSet: NewConferenceStyle.addParticipant,
secure: secureSwitch.checked,
visible: true,
secureIconVisibleHandler : function(entry) {
return UtilsCpp.hasCapability(entry.sipAddress, LinphoneEnums.FriendCapabilityLimeX3Dh)
},
handler: function (entry) {
selectedParticipants.addAddress(entry.sipAddress)
smartSearchBar.addAddressToIgnore(entry.sipAddress);
},
}]
onEntryClicked: {
selectedParticipants.addAddress(entry.sipAddress)
smartSearchBar.addAddressToIgnore(entry.sipAddress);
}
}
Text{
Layout.preferredHeight: 20
Layout.rightMargin: 65
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
Layout.topMargin: ConferenceManagerStyle.columns.selector.spacing
//: 'Admin' : Admin(istrator)
//~ one word for admin status
text : qsTr('adminStatus')
color: NewConferenceStyle.addressesAdminColor
font.pointSize: Units.dp * 11
font.weight: Font.Light
visible: participantView.count > 0
}
ScrollableListViewField {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.bottomMargin: 5
textFieldStyle: TextFieldStyle.unbordered
ParticipantsView {
id: participantView
anchors.fill: parent
showContactAddress:false
showSwitch : true
showSeparator: false
isSelectable: false
showInvitingIndicator: false
function removeParticipant(entry){
smartSearchBar.removeAddressToIgnore(entry.sipAddress)
selectedParticipants.removeModel(entry)
++lastContacts.reloadCount
}
actions: [{
colorSet: NewConferenceStyle.removeParticipant,
secure:0,
visible:true,
//: 'Remove this participant from the selection' : Explanation about removing participant from a selection
//~ Tooltip This is a tooltip
tooltipText: qsTr('removeParticipantSelection'),
handler: function (entry) {
removeParticipant(entry)
}
}]
genSipAddress: ''
model: ParticipantProxyModel {
id:selectedParticipants
chatRoomModel:null
}
onEntryClicked: actions[0].handler(entry)
}
}
}
}
Item{
Layout.fillWidth: true
Layout.preferredHeight: 20
Text{
anchors.fill:parent
textFormat: Text.RichText
//: 'Required' : Word relative to a star to explain that it is a requirement (Field form)
text : '<span style="color:red">*</span> '+qsTr('requiredField')
//font.weight: Font.DemiBold
color: NewConferenceStyle.requiredColor
font.pointSize: Units.dp * 8
}
}
}
//----------------------------------------------------
// STACKVIEWS
//----------------------------------------------------
Component{
id: datePicker
DatePicker{
onClicked: {
dateField.setDate(date)
rightStackView.currentItemType = 0
rightStackView.pop()
}
}
}
Component{
id: timePicker
TimePicker{
onClicked: {
timeField.setTime(date)
rightStackView.currentItemType = 0
rightStackView.pop()
}
}
}
}
}
}

View file

@ -115,15 +115,8 @@ function updateSelectedEntry (view, props) {
menu.resetSelectedEntry()
} else if (view === 'Contacts') {
item.contactsEntry.select()
//timeline.resetSelectedEntry()
} else {
//menu.resetSelectedEntry()
/*
if (view === 'Conversation') {
timeline.setSelectedEntry(props.peerAddress, props.localAddress)
} else if (view === 'ContactEdit') {
timeline.resetSelectedEntry()
}*/
} else if (view === 'Conferences') {
item.contactsEntry.select()
}
}

View file

@ -223,7 +223,12 @@ ApplicationWindow {
tooltipText:qsTr('newConferenceButton')
//autoIcon: true
onClicked: Logic.openConferenceManager()
//onClicked: Logic.openConferenceManager()
onClicked: {
window.detachVirtualWindow()
window.attachVirtualWindow(Qt.resolvedUrl('Dialogs/NewConference.qml')
,{})
}
}
ActionButton {
@ -296,17 +301,32 @@ ApplicationWindow {
}
}
/*
ApplicationMenuEntry {
visible : false //TODO
id: conferencesEntry
icon: MainWindowStyle.menu.conferencesIcon
icon: MainWindowStyle.menu.conferences.icon
iconSize: MainWindowStyle.menu.conferences.iconSize
overwriteColor: isSelected ? MainWindowStyle.menu.conferences.selectedColor : MainWindowStyle.menu.conferences.color
name: 'MES CONFERENCES'
overwriteColor: isSelected ? MainWindowStyle.menu.conferencesSelectedColor : MainWindowStyle.menu.conferencesColor
visible: SettingsModel.conferencesEnabled
onSelected: window.setView('HistoryView')
}*/
onSelected: {
timeline.model.unselectAll()
setView('Conferences')
}
onClicked:{
setView('Conferences')
}
Icon{
anchors.right:parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: 10
icon: MainWindowStyle.menu.direction.icon
overwriteColor: conferencesEntry.overwriteColor
iconSize: MainWindowStyle.menu.direction.iconSize
}
}
}
// History.

View file

@ -40,7 +40,7 @@ QtObject {
property QtObject newConference: QtObject {
property int iconSize: 40
property string name : 'newConference'
property string icon : 'new_conference_custom'
property string icon : 'conference_custom'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'ma_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'ma_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'ma_p_b_bg').color

View file

@ -0,0 +1,429 @@
pragma Singleton
import QtQml 2.2
import Units 1.0
import ColorsList 1.0
// =============================================================================
QtObject {
property string sectionName: 'VideoConference'
property color backgroundColor: ColorsList.add(sectionName+'_description', '', '', '#798791').color
property QtObject title: QtObject {
property color color: ColorsList.add(sectionName+'_title', 'q').color
property int pointSize: Units.dp * 11
}
property QtObject grid: QtObject {
property int spacing: 5
property QtObject cell: QtObject {
property int height: 145
property int spacing: 5
property int width: 154
property QtObject contactDescription: QtObject {
property int height: 35
}
}
}
property QtObject actionArea: QtObject {
property int height: 100
property int iconSize: 40
property int leftButtonsGroupMargin: 50
property int lowWidth: 650
property int rightButtonsGroupMargin: 50
property QtObject userVideo: QtObject {
property int height: 200
property int width: 130
property int heightReference: 1200 // height and width are fixed from these references
property int widthReference: 780
}
property QtObject vu: QtObject {
property int spacing: 5
}
property QtObject callError: QtObject {
property color color: ColorsList.add(sectionName+'_action_error', 'i').color
property int pointSize: Units.dp * 12
}
}
property QtObject container: QtObject {
property int margins: 15
property QtObject avatar: QtObject {
property color backgroundColor: ColorsList.add(sectionName+'_container_avatar_bg', 'n').color
property int maxSize: 300
}
property QtObject pause: QtObject {
property color color: ColorsList.add(sectionName+'_container_pause', 'g90').color
property QtObject text: QtObject {
property color color: ColorsList.add(sectionName+'_container_pause_text', 'q').color
property int pointSizeFactor: 5
}
}
}
property QtObject header: QtObject {
property int buttonIconSize: 40
property int iconSize: 16
property int leftMargin: 20
property int rightMargin: 20
property int spacing: 10
property int topMargin: 26
property QtObject busyIndicator: QtObject {
property color color: ColorsList.add(sectionName+'_header_busy', 'g').color
property int height: 30
property int width: 30
}
property QtObject contactDescription: QtObject {
property int height: 50
property int width: 150
}
property QtObject elapsedTime: QtObject {
property color color: ColorsList.add(sectionName+'_header_elapsed_time', 'j').color
property int pointSize: Units.dp * 10
property QtObject fullscreen: QtObject {
property int pointSize: Units.dp * 12
}
}
property QtObject stats: QtObject {
property int relativeY: 90
}
}
property QtObject zrtpArea: QtObject {
property int height: 50
property QtObject buttons: QtObject {
property int spacing: 10
}
property QtObject text: QtObject {
property color colorA: ColorsList.add(sectionName+'_zrtp_text_a', 'j').color
property color colorB: ColorsList.add(sectionName+'_zrtp_text_b', 'i').color
property int pointSize: Units.dp * 10
property int wordsSpacing: 5
}
}
// Button colors
property QtObject buttons: QtObject {
property QtObject callsList: QtObject {
property int iconSize: 40
property string name : 'callsList'
property string icon : 'call_menu_custom'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color
}
property QtObject dialpad: QtObject {
property int iconSize: 40
property string name : 'dialpad'
property string icon : 'dialpad_custom'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color
}
property QtObject screenSharing: QtObject {
property int iconSize: 40
property string icon : 'screen_sharing_custom'
property string name : 'screenSharing'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'sc_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'sc_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'sc_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'sc_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'sc_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'sc_p_b_fg').color
}
property QtObject recordOn: QtObject {
property int iconSize: 40
property string icon : 'record_custom'
property string name : 'recordOn'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'sc_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'sc_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'sc_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'sc_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'sc_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'sc_p_b_fg').color
}
property QtObject recordOff: QtObject {
property int iconSize: 40
property string icon : 'record_custom'
property string name : 'recordOff'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'sc_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'sc_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'sc_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'sc_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'sc_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'sc_p_b_fg').color
}
property QtObject screenshot: QtObject {
property int iconSize: 40
property string icon : 'screenshot_custom'
property string name : 'screenshot'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'sc_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'sc_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'sc_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'sc_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'sc_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'sc_p_b_fg').color
}
property QtObject fullscreen: QtObject {
property int iconSize: 40
property string icon : 'fullscreen_custom'
property string name : 'fullscreen'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'sc_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'sc_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'sc_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'sc_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'sc_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'sc_p_b_fg').color
}
property QtObject stopFullscreen: QtObject {
property int iconSize: 40
property string icon : 'stop_fullscreen_custom'
property string name : 'stopFullscreen'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'sc_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'sc_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'sc_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'sc_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'sc_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'sc_p_b_fg').color
}
//------------------------------------------------------------------------------
property QtObject secure: QtObject {
property int buttonSize: 40
property int iconSize: 20
property string icon : ''
property string name : 'secure'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, '', '', '#66727B').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, '', '', '#66727B').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, '', '', '#66727B').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, '', '', 'transparent').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, '', '', 'transparent').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, '', '', 'transparent').color
}
property QtObject unsecure: QtObject {
property int iconSize: 16
property string icon : 'call_chat_unsecure_custom'
property string name : 'unsecure'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, '', '', 'transparent').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, '', '', 'transparent').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, '', '', 'transparent').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, '', '', '#ff0000').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, '', '', '#ff0000').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, '', '', '#ff0000').color
}
property QtObject microOn: QtObject {
property int iconSize: 40
property string icon : 'micro_on_custom'
property string name : 'microOn'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_h_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_n_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_h_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_n_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color
}
property QtObject microOff: QtObject {
property int iconSize: 40
property string icon : 'micro_off_custom'
property string name : 'microOff'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_h_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_n_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_h_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_n_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color
}
property QtObject speakerOn: QtObject {
property int iconSize: 40
property string icon : 'speaker_on_custom'
property string name : 'speakerOn'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_h_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_n_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_h_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_n_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color
}
property QtObject speakerOff: QtObject {
property int iconSize: 40
property string icon : 'speaker_off_custom'
property string name : 'speakerOff'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_h_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_n_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_h_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_n_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color
}
property QtObject cameraOn: QtObject {
property int iconSize: 40
property string icon : 'camera_on_custom'
property string name : 'cameraOn'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_h_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_n_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color
property color backgroundUpdatingColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_u', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_h_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_n_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color
property color foregroundUpdatingColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_u', icon, 's_p_b_fg').color
}
property QtObject cameraOff: QtObject {
property int iconSize: 40
property string icon : 'camera_off_custom'
property string name : 'cameraOff'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_h_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_n_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color
property color backgroundUpdatingColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_u', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_h_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_n_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color
property color foregroundUpdatingColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_u', icon, 's_p_b_fg').color
}
property QtObject pause: QtObject {
property int iconSize: 40
property string icon : 'pause_custom'
property string name : 'pause'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color
property color backgroundUpdatingColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_u', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color
property color foregroundUpdatingColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_u', icon, 's_p_b_fg').color
}
property QtObject play: QtObject {
property int iconSize: 40
property string icon : 'play_custom'
property string name : 'play'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color
property color backgroundUpdatingColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_u', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_n_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color
property color foregroundUpdatingColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_u', icon, 's_p_b_fg').color
}
property QtObject hangup: QtObject {
property int iconSize: 40
property string icon : 'hangup_custom'
property string name : 'hangup'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'r_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'r_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'r_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'r_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'r_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'r_p_b_fg').color
}
//------------------------------------------------------------------------------
property QtObject chat: QtObject {
property int iconSize: 40
property string icon : 'chat_custom'
property string name : 'chat'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'me_n_b_inv_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'me_h_b_inv_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'me_p_b_inv_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'me_n_b_inv_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'me_h_b_inv_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'me_p_b_inv_fg').color
}
property QtObject participants: QtObject {
property int iconSize: 40
property string icon : 'participants_custom'
property string name : 'participants'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'me_n_b_inv_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'me_h_b_inv_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'me_p_b_inv_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'me_n_b_inv_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'me_h_b_inv_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'me_p_b_inv_fg').color
}
property QtObject callQuality: QtObject {
property int iconSize: 20
property string name : 'quality'
property string icon : 'call_quality_custom'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'me_n_b_bg').color
property color backgroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_d', icon, 'me_d_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'me_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'me_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'me_n_b_fg').color
property color foregroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_d', icon, 'me_d_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'me_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'me_p_b_fg').color
}
property QtObject options: QtObject {
property int iconSize: 40
property string icon : 'options_custom'
property string name : 'options'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'me_n_b_inv_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'me_h_b_inv_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'me_p_b_inv_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'me_n_b_inv_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'me_h_b_inv_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'me_p_b_inv_fg').color
}
//------------------------------------------------------------------------------
property QtObject history: QtObject {
property int iconSize: 40
property string icon : 'history_custom'
property string name : 'history'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color
}
property QtObject acceptVideoCall: QtObject {
property int iconSize: 40
property string icon : 'video_call_accept_custom'
property string name : 'videoCallAccept'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'a_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'a_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'a_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'a_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'a_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'a_p_b_fg').color
}
property QtObject acceptCall: QtObject {
property int iconSize: 40
property string icon : 'call_accept_custom'
property string name : 'callAccept'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'a_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'a_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'a_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'a_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'a_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'a_p_b_fg').color
}
}
}

View file

@ -0,0 +1,146 @@
pragma Singleton
import QtQml 2.2
import Units 1.0
import ColorsList 1.0
// =============================================================================
QtObject {
property string sectionName: 'Conferences'
property color backgroundColor: ColorsList.add(sectionName+'_bg', 'k').color
property int spacing: 20
property QtObject filter: QtObject {
property string icon: 'filter_custom'
property color color: ColorsList.add(sectionName+'_filter_icon', 'c').color
}
property QtObject bar: QtObject {
property color backgroundColor: ColorsList.add(sectionName+'_bar_bg', 'e').color
property int height: 60
property int leftMargin: 18
property int rightMargin: 18
}
property QtObject conference: QtObject {
property string name: 'conference'
property int actionButtonsSize: 36
property int avatarSize: 30
property int deleteButtonSize: 22
property int height: 50
property int leftMargin: 40
property int bottomMargin: 10
property int presenceLevelSize: 12
property int rightMargin: 25
property int spacing: 15
property QtObject backgroundColor: QtObject {
property color normal: ColorsList.add(sectionName+'_conference_bg_n', 'conference_bg').color
property color hovered: ColorsList.add(sectionName+'_conference_bg_h', 'g10').color
}
property QtObject border: QtObject {
property color color: ColorsList.add(sectionName+'_conference_border', 'f').color
property int width: 1
}
property QtObject indicator: QtObject {
property color color: ColorsList.add(sectionName+'_conference_indicator', 'i').color
property int width: 5
}
property QtObject schedule: QtObject {
property int pointSize: Units.dp * 10
property string icon : 'schedule_custom'
property int iconSize: 30
property color color: ColorsList.add(sectionName+'_schedule', 'j').color
}
property QtObject participants: QtObject {
property int pointSize: Units.dp * 10
property string icon : 'contact_custom'
property int iconSize: 30
property color color: ColorsList.add(sectionName+'_participants', 'j').color
}
property QtObject organizer: QtObject {
property color color: ColorsList.add(sectionName+'_conference_organizer', 'j').color
property int pointSize: Units.dp * 10
property int width: 220
}
}
property QtObject sectionHeading: QtObject {
property string name: 'sectionHeading'
property int padding: 5
property int bottomMargin: 20
property QtObject border: QtObject {
property color color: ColorsList.add(sectionName+'_sectionHeading_border', 'g10').color
property int width: 1
}
property QtObject text: QtObject {
property int pointSize: Units.dp * 10
property color color: ColorsList.add(sectionName+'_sectionHeading_text', 'ab').color
}
}
/*
property QtObject schedule: QtObject {
property int iconSize: 36
property string icon : 'schedule_custom'
property string name : 'schedule'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color
}*/
//----------------------------------------------------------------------------------
property QtObject videoCall: QtObject {
property int iconSize: 36
property string name : 'videoCall'
property string icon : 'video_call_custom'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color
}
property QtObject call: QtObject {
property int iconSize: 36
property string name : 'call'
property string icon : 'call_custom'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color
}
property QtObject chat: QtObject {
property int iconSize: 36
property string name : 'chat'
property string icon : 'chat_custom'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 's_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 's_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 's_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 's_p_b_fg').color
}
property QtObject deleteAction: QtObject {
property int iconSize: 36
property string name : 'delete'
property string icon : 'contact_delete_custom'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'me_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'me_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'me_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'me_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'me_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'me_p_b_fg').color
}
}

View file

@ -0,0 +1,43 @@
pragma Singleton
import QtQml 2.2
import QtQuick 2.7
import Units 1.0
import ColorsList 1.0
// =============================================================================
QtObject {
property string sectionName: 'NewConference'
property color askEncryptionColor: ColorsList.add(sectionName+'_ask_encryption', 'g').color
property color subjectTitleColor: ColorsList.add(sectionName+'_subject_title', 'g').color
property color recentContactTitleColor: ColorsList.add(sectionName+'_recent_contact_title', 'g').color
property color recentContactUsernameColor: ColorsList.add(sectionName+'_recent_contact_username', 'g').color
property color addressesBorderColor: ColorsList.add(sectionName+'_addresses_border', 'l').color
property color addressesAdminColor: ColorsList.add(sectionName+'_addresses_admin', 'g').color
property color requiredColor: ColorsList.add(sectionName+'_required_text', 'g').color
property QtObject addParticipant: QtObject {
property int iconSize: 30
property string name : 'addParticipant'
property string icon : 'add_participant_custom'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'l_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'l_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'l_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'l_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'l_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'l_p_b_fg').color
}
property QtObject removeParticipant: QtObject {
property int iconSize: 30
property string name : 'removeParticipant'
property string icon : 'remove_participant_custom'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'l_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'l_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'l_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'l_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'l_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'l_p_b_fg').color
}
}

View file

@ -43,7 +43,13 @@ QtObject {
property int iconSize: 50
property color color: ColorsList.add(sectionName+'_me_contacts', 'me_n_b_inv_fg').color
property color selectedColor: ColorsList.add(sectionName+'_me_contacts_c', 'me_p_b_inv_fg').color
}
}
property QtObject conferences: QtObject {
property string icon: 'conference_custom'
property int iconSize: 50
property color color: ColorsList.add(sectionName+'_me_conferences', 'me_n_b_inv_fg').color
property color selectedColor: ColorsList.add(sectionName+'_me_conferences_c', 'me_p_b_inv_fg').color
}
/*
property string conferencesIcon: 'conference'
property color conferencesColor: ColorsList.add(sectionName+'_me_confs', 'me_n_b_inv_fg').color
@ -91,7 +97,7 @@ QtObject {
property QtObject newConference: QtObject {
property int iconSize: 40
property string name : 'newConference'
property string icon : 'new_conference_custom'
property string icon : 'conference_custom'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'ma_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'ma_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'ma_p_b_bg').color

View file

@ -10,6 +10,7 @@ singleton CallFullscreenStyle 1.0 Calls/CallFullscree
singleton CallStyle 1.0 Calls/CallStyle.qml
singleton CallsWindowStyle 1.0 Calls/CallsWindowStyle.qml
singleton ConferenceStyle 1.0 Calls/ConferenceStyle.qml
singleton VideoConferenceStyle 1.0 Calls/VideoConferenceStyle.qml
singleton CallSipAddressStyle 1.0 Calls/Dialogs/CallSipAddressStyle.qml
singleton CallTransferStyle 1.0 Calls/Dialogs/CallTransferStyle.qml
@ -26,6 +27,7 @@ singleton CreateAppSipAccountStyle 1.0 Main/Assistant/Crea
singleton UseAppSipAccountStyle 1.0 Main/Assistant/UseAppSipAccountStyle.qml
singleton AssistantStyle 1.0 Main/AssistantStyle.qml
singleton ConferencesStyle 1.0 Main/ConferencesStyle.qml
singleton ContactEditStyle 1.0 Main/ContactEditStyle.qml
singleton ContactsStyle 1.0 Main/ContactsStyle.qml
singleton ConversationStyle 1.0 Main/ConversationStyle.qml
@ -41,6 +43,7 @@ singleton InfoChatRoomStyle 1.0 Main/Dialogs/InfoCh
singleton InfoEncryptionStyle 1.0 Main/Dialogs/InfoEncryptionStyle.qml
singleton ManageAccountsStyle 1.0 Main/Dialogs/ManageAccountsStyle.qml
singleton NewChatRoomStyle 1.0 Main/Dialogs/NewChatRoomStyle.qml
singleton NewConferenceStyle 1.0 Main/Dialogs/NewConferenceStyle.qml
singleton ParticipantsDevicesStyle 1.0 Main/Dialogs/ParticipantsDevicesStyle.qml