diff --git a/linphone-app/assets/languages/da.ts b/linphone-app/assets/languages/da.ts index 48c5aab62..375bbc7d6 100644 --- a/linphone-app/assets/languages/da.ts +++ b/linphone-app/assets/languages/da.ts @@ -1543,6 +1543,90 @@ Klik her: <a href="%1">%1</a> + + NewConference + + cancelButton + 'Cancel' : Cancel button + + + + startButton + 'Launch' : Start button + + + + missingSubject + 'You need to fill a subject.' : Tooltip to warn a user on missing field. + + + + missingParticipants + 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. + + + + + + + missingConferenceURI + '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. + + + + newConferenceTitle + 'Start a video conference' : Title of a popup about creation of a video conference + + + + subjectLabel + 'Subject' : Label of a text field about the subject of the chat room + + + + subjectPlaceholder + 'Give a subject' : Placeholder in a form about setting a subject + + + + subjectTooltip + 'Current subject of the Chat Room. It cannot be empty' + + Explanation about the subject of the chat room + + + askEncryption + 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. + + + + participantSelectionPlaceholder + 'Select participants' : Placeholder for a search on participant to add them in selection. + + + + participantSelectionTooltip + 'Search in your contacts or add a custom one to the chat room.' + + + + adminStatus + 'Admin' : Admin(istrator) + + word for admin status + + + removeParticipantSelection + 'Remove this participant from the selection' : Explanation about removing participant from a selection + + This is a tooltip + + + requiredField + 'Required' : Word relative to a star to explain that it is a requirement (Field form) + + + Notice diff --git a/linphone-app/assets/languages/de.ts b/linphone-app/assets/languages/de.ts index 7916a2717..30d2db494 100644 --- a/linphone-app/assets/languages/de.ts +++ b/linphone-app/assets/languages/de.ts @@ -1543,6 +1543,90 @@ Klicken Sie hier: <a href="%1">%1</a> Letzte Kontakte + + NewConference + + cancelButton + 'Cancel' : Cancel button + ABBRECHEN + + + startButton + 'Launch' : Start button + START + + + missingSubject + 'You need to fill a subject.' : Tooltip to warn a user on missing field. + Sie müssen ein Thema eintragen. + + + missingParticipants + 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. + + Sie benötigen mindestens %1 Teilnehmer. + Sie benötigen mindestens %1 Teilnehmer. + + + + missingConferenceURI + '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. + Sie müssen eine Konferenz-URI in den Kontoeinstellungen festlegen um einen konferenzbasierten Chatraum zu erstellen. + + + newConferenceTitle + 'Start a video conference' : Title of a popup about creation of a video conference + + + + subjectLabel + 'Subject' : Label of a text field about the subject of the chat room + Betreff + + + subjectPlaceholder + 'Give a subject' : Placeholder in a form about setting a subject + Betreff eingeben + + + subjectTooltip + 'Current subject of the Chat Room. It cannot be empty' + Aktuelles Thema des Chatraums. Darf nicht leer sein. + Explanation about the subject of the chat room + + + askEncryption + 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. + Möchten Sie den Chat verschlüsseln? + + + participantSelectionPlaceholder + 'Select participants' : Placeholder for a search on participant to add them in selection. + Wähle Teilnehmer + + + participantSelectionTooltip + 'Search in your contacts or add a custom one to the chat room.' + In Kontakten suchen oder einen eigenen zum Chatraum hinzufügen. + + + adminStatus + 'Admin' : Admin(istrator) + Administrator + word for admin status + + + removeParticipantSelection + 'Remove this participant from the selection' : Explanation about removing participant from a selection + Teilnehmer aus Auswahl entfernen + This is a tooltip + + + requiredField + 'Required' : Word relative to a star to explain that it is a requirement (Field form) + Erforderlich + + Notice diff --git a/linphone-app/assets/languages/en.ts b/linphone-app/assets/languages/en.ts index ba43995e2..d83a142a0 100644 --- a/linphone-app/assets/languages/en.ts +++ b/linphone-app/assets/languages/en.ts @@ -1543,6 +1543,90 @@ Click here: <a href="%1">%1</a> Recent contacts + + NewConference + + cancelButton + 'Cancel' : Cancel button + CANCEL + + + startButton + 'Launch' : Start button + + + + missingSubject + 'You need to fill a subject.' : Tooltip to warn a user on missing field. + You need to fill a subject. + + + missingParticipants + 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. + + You need at least %1 participant. + You need at least %1 participants. + + + + missingConferenceURI + '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. + You need to set the conference URI in your account settings to create a conference based chat room. + + + newConferenceTitle + 'Start a video conference' : Title of a popup about creation of a video conference + + + + subjectLabel + 'Subject' : Label of a text field about the subject of the chat room + Subject + + + subjectPlaceholder + 'Give a subject' : Placeholder in a form about setting a subject + Give a subject + + + subjectTooltip + 'Current subject of the Chat Room. It cannot be empty' + Current subject of the Chat Room. It cannot be empty. + Explanation about the subject of the chat room + + + askEncryption + 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. + Would you like to encrypt your chat? + + + participantSelectionPlaceholder + 'Select participants' : Placeholder for a search on participant to add them in selection. + Select participants + + + participantSelectionTooltip + 'Search in your contacts or add a custom one to the chat room.' + Search in your contacts or add a custom one to the chat room. + + + adminStatus + 'Admin' : Admin(istrator) + Admin + word for admin status + + + removeParticipantSelection + 'Remove this participant from the selection' : Explanation about removing participant from a selection + Remove this participant from the selection + This is a tooltip + + + requiredField + 'Required' : Word relative to a star to explain that it is a requirement (Field form) + Required + + Notice diff --git a/linphone-app/assets/languages/es.ts b/linphone-app/assets/languages/es.ts index 2c195c471..9e7fae26a 100644 --- a/linphone-app/assets/languages/es.ts +++ b/linphone-app/assets/languages/es.ts @@ -1543,6 +1543,90 @@ Haga clic aquí: <a href="%1">%1 </a> + + NewConference + + cancelButton + 'Cancel' : Cancel button + + + + startButton + 'Launch' : Start button + + + + missingSubject + 'You need to fill a subject.' : Tooltip to warn a user on missing field. + + + + missingParticipants + 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. + + + + + + + missingConferenceURI + '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. + + + + newConferenceTitle + 'Start a video conference' : Title of a popup about creation of a video conference + + + + subjectLabel + 'Subject' : Label of a text field about the subject of the chat room + + + + subjectPlaceholder + 'Give a subject' : Placeholder in a form about setting a subject + + + + subjectTooltip + 'Current subject of the Chat Room. It cannot be empty' + + Explanation about the subject of the chat room + + + askEncryption + 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. + + + + participantSelectionPlaceholder + 'Select participants' : Placeholder for a search on participant to add them in selection. + + + + participantSelectionTooltip + 'Search in your contacts or add a custom one to the chat room.' + + + + adminStatus + 'Admin' : Admin(istrator) + + word for admin status + + + removeParticipantSelection + 'Remove this participant from the selection' : Explanation about removing participant from a selection + + This is a tooltip + + + requiredField + 'Required' : Word relative to a star to explain that it is a requirement (Field form) + + + Notice diff --git a/linphone-app/assets/languages/fr_FR.ts b/linphone-app/assets/languages/fr_FR.ts index 5d12e998e..73e851847 100644 --- a/linphone-app/assets/languages/fr_FR.ts +++ b/linphone-app/assets/languages/fr_FR.ts @@ -1543,6 +1543,90 @@ Cliquez ici : <a href="%1">%1</a> Contacts récents + + NewConference + + cancelButton + 'Cancel' : Cancel button + ANNULER + + + startButton + 'Launch' : Start button + LANCER + + + missingSubject + 'You need to fill a subject.' : Tooltip to warn a user on missing field. + Vous devez définir un sujet. + + + missingParticipants + 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. + + Vous devez ajouter au moins %1 participant. + Vous devez ajouter au moins %1 participants. + + + + missingConferenceURI + '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. + Vous devez définir l'URI de la conférence dans les paramètres de votre compte pour créer une conférence. + + + newConferenceTitle + 'Start a video conference' : Title of a popup about creation of a video conference + + + + subjectLabel + 'Subject' : Label of a text field about the subject of the chat room + Sujet + + + subjectPlaceholder + 'Give a subject' : Placeholder in a form about setting a subject + Définissez un sujet + + + subjectTooltip + 'Current subject of the Chat Room. It cannot be empty' + Sujet de la conversation. Il ne peut pas être vide. + Explanation about the subject of the chat room + + + askEncryption + 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. + Voulez-vous chiffrer votre conversation ? + + + participantSelectionPlaceholder + 'Select participants' : Placeholder for a search on participant to add them in selection. + Choisissez les participants + + + participantSelectionTooltip + 'Search in your contacts or add a custom one to the chat room.' + Chercher dans vos contacts ou ajouter à la main dans la conversation. + + + adminStatus + 'Admin' : Admin(istrator) + Admin + word for admin status + + + removeParticipantSelection + 'Remove this participant from the selection' : Explanation about removing participant from a selection + Enlever ce participant de la sélection + This is a tooltip + + + requiredField + 'Required' : Word relative to a star to explain that it is a requirement (Field form) + Obligatoire + + Notice diff --git a/linphone-app/assets/languages/hu.ts b/linphone-app/assets/languages/hu.ts index a9f2708a1..1c703f6c5 100644 --- a/linphone-app/assets/languages/hu.ts +++ b/linphone-app/assets/languages/hu.ts @@ -1533,6 +1533,89 @@ Kattintson ide: <a href="%1">%1</a> Legutóbbi névjegyek + + NewConference + + cancelButton + 'Cancel' : Cancel button + Mégse + + + startButton + 'Launch' : Start button + Indítás + + + missingSubject + 'You need to fill a subject.' : Tooltip to warn a user on missing field. + Ki kell töltenie egy témát. + + + missingParticipants + 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. + + Legalább %1 résztvevő szükséges. + + + + missingConferenceURI + '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. + Konferenciaalapú csevegőszoba létrehozásához be kell állítania a konferencia URI-címét a fiókbeállításokban. + + + newConferenceTitle + 'Start a video conference' : Title of a popup about creation of a video conference + + + + subjectLabel + 'Subject' : Label of a text field about the subject of the chat room + Téma + + + subjectPlaceholder + 'Give a subject' : Placeholder in a form about setting a subject + Téma hozzáadása + + + subjectTooltip + 'Current subject of the Chat Room. It cannot be empty' + A csevegőszoba jelenlegi témája. Nem lehet üres. + Explanation about the subject of the chat room + + + askEncryption + 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. + Szeretné titkosítani a csevegését? + + + participantSelectionPlaceholder + 'Select participants' : Placeholder for a search on participant to add them in selection. + Résztvevők kiválasztása + + + participantSelectionTooltip + 'Search in your contacts or add a custom one to the chat room.' + Keressen a névjegyek között vagy adjon hozzá egy egyediet a csevegőszobához. + + + adminStatus + 'Admin' : Admin(istrator) + Felügyelet + word for admin status + + + removeParticipantSelection + 'Remove this participant from the selection' : Explanation about removing participant from a selection + Távolítsa el ezt a résztvevőt a kiválasztásból + This is a tooltip + + + requiredField + 'Required' : Word relative to a star to explain that it is a requirement (Field form) + Kötelező + + Notice diff --git a/linphone-app/assets/languages/it.ts b/linphone-app/assets/languages/it.ts index b5c57b01e..0d8f5103b 100644 --- a/linphone-app/assets/languages/it.ts +++ b/linphone-app/assets/languages/it.ts @@ -1543,6 +1543,90 @@ Clicca: <a href="%1">%1</a> + + NewConference + + cancelButton + 'Cancel' : Cancel button + + + + startButton + 'Launch' : Start button + + + + missingSubject + 'You need to fill a subject.' : Tooltip to warn a user on missing field. + + + + missingParticipants + 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. + + + + + + + missingConferenceURI + '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. + + + + newConferenceTitle + 'Start a video conference' : Title of a popup about creation of a video conference + + + + subjectLabel + 'Subject' : Label of a text field about the subject of the chat room + + + + subjectPlaceholder + 'Give a subject' : Placeholder in a form about setting a subject + + + + subjectTooltip + 'Current subject of the Chat Room. It cannot be empty' + + Explanation about the subject of the chat room + + + askEncryption + 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. + + + + participantSelectionPlaceholder + 'Select participants' : Placeholder for a search on participant to add them in selection. + + + + participantSelectionTooltip + 'Search in your contacts or add a custom one to the chat room.' + + + + adminStatus + 'Admin' : Admin(istrator) + + word for admin status + + + removeParticipantSelection + 'Remove this participant from the selection' : Explanation about removing participant from a selection + + This is a tooltip + + + requiredField + 'Required' : Word relative to a star to explain that it is a requirement (Field form) + + + Notice diff --git a/linphone-app/assets/languages/ja.ts b/linphone-app/assets/languages/ja.ts index 07c8d13bf..595a5cb06 100644 --- a/linphone-app/assets/languages/ja.ts +++ b/linphone-app/assets/languages/ja.ts @@ -1533,6 +1533,89 @@ + + NewConference + + cancelButton + 'Cancel' : Cancel button + + + + startButton + 'Launch' : Start button + + + + missingSubject + 'You need to fill a subject.' : Tooltip to warn a user on missing field. + + + + missingParticipants + 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. + + + + + + missingConferenceURI + '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. + + + + newConferenceTitle + 'Start a video conference' : Title of a popup about creation of a video conference + + + + subjectLabel + 'Subject' : Label of a text field about the subject of the chat room + + + + subjectPlaceholder + 'Give a subject' : Placeholder in a form about setting a subject + + + + subjectTooltip + 'Current subject of the Chat Room. It cannot be empty' + + Explanation about the subject of the chat room + + + askEncryption + 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. + + + + participantSelectionPlaceholder + 'Select participants' : Placeholder for a search on participant to add them in selection. + + + + participantSelectionTooltip + 'Search in your contacts or add a custom one to the chat room.' + + + + adminStatus + 'Admin' : Admin(istrator) + + word for admin status + + + removeParticipantSelection + 'Remove this participant from the selection' : Explanation about removing participant from a selection + + This is a tooltip + + + requiredField + 'Required' : Word relative to a star to explain that it is a requirement (Field form) + + + Notice diff --git a/linphone-app/assets/languages/lt.ts b/linphone-app/assets/languages/lt.ts index fa6c7ef0a..39b5829b3 100644 --- a/linphone-app/assets/languages/lt.ts +++ b/linphone-app/assets/languages/lt.ts @@ -1553,6 +1553,91 @@ Spustelėkite čia: <a href="%1">%1</a> + + NewConference + + cancelButton + 'Cancel' : Cancel button + + + + startButton + 'Launch' : Start button + + + + missingSubject + 'You need to fill a subject.' : Tooltip to warn a user on missing field. + + + + missingParticipants + 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. + + + + + + + + missingConferenceURI + '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. + + + + newConferenceTitle + 'Start a video conference' : Title of a popup about creation of a video conference + + + + subjectLabel + 'Subject' : Label of a text field about the subject of the chat room + + + + subjectPlaceholder + 'Give a subject' : Placeholder in a form about setting a subject + + + + subjectTooltip + 'Current subject of the Chat Room. It cannot be empty' + + Explanation about the subject of the chat room + + + askEncryption + 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. + + + + participantSelectionPlaceholder + 'Select participants' : Placeholder for a search on participant to add them in selection. + + + + participantSelectionTooltip + 'Search in your contacts or add a custom one to the chat room.' + + + + adminStatus + 'Admin' : Admin(istrator) + + word for admin status + + + removeParticipantSelection + 'Remove this participant from the selection' : Explanation about removing participant from a selection + + This is a tooltip + + + requiredField + 'Required' : Word relative to a star to explain that it is a requirement (Field form) + + + Notice diff --git a/linphone-app/assets/languages/pt_BR.ts b/linphone-app/assets/languages/pt_BR.ts index 5502f32e9..446c36e11 100644 --- a/linphone-app/assets/languages/pt_BR.ts +++ b/linphone-app/assets/languages/pt_BR.ts @@ -1543,6 +1543,90 @@ Clique aqui: <a href="%1">%1 </a> Contatos recentes + + NewConference + + cancelButton + 'Cancel' : Cancel button + CANCELAR + + + startButton + 'Launch' : Start button + + + + missingSubject + 'You need to fill a subject.' : Tooltip to warn a user on missing field. + Você precisa preencher um assunto. + + + missingParticipants + 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. + + Você precisa de pelo menos %1 participante. + Você precisa de pelo menos %1 participantes. + + + + missingConferenceURI + '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. + 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. + + + newConferenceTitle + 'Start a video conference' : Title of a popup about creation of a video conference + + + + subjectLabel + 'Subject' : Label of a text field about the subject of the chat room + Assunto + + + subjectPlaceholder + 'Give a subject' : Placeholder in a form about setting a subject + Dê um assunto + + + subjectTooltip + 'Current subject of the Chat Room. It cannot be empty' + Assunto atual da sala de bate-papo. Não pode estar vazio. + Explanation about the subject of the chat room + + + askEncryption + 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. + Você gostaria de criptografar seu bate-papo? + + + participantSelectionPlaceholder + 'Select participants' : Placeholder for a search on participant to add them in selection. + Selecionar os participantes + + + participantSelectionTooltip + 'Search in your contacts or add a custom one to the chat room.' + Pesquise em seus contatos ou adicione um personalizado à sala de chat. + + + adminStatus + 'Admin' : Admin(istrator) + Admin + word for admin status + + + removeParticipantSelection + 'Remove this participant from the selection' : Explanation about removing participant from a selection + Remover este participante da seleção + This is a tooltip + + + requiredField + 'Required' : Word relative to a star to explain that it is a requirement (Field form) + Obrigatório + + Notice diff --git a/linphone-app/assets/languages/ru.ts b/linphone-app/assets/languages/ru.ts index becb77c7c..38afc7369 100644 --- a/linphone-app/assets/languages/ru.ts +++ b/linphone-app/assets/languages/ru.ts @@ -1553,6 +1553,91 @@ Недавние контакты + + NewConference + + cancelButton + 'Cancel' : Cancel button + + + + startButton + 'Launch' : Start button + + + + missingSubject + 'You need to fill a subject.' : Tooltip to warn a user on missing field. + + + + missingParticipants + 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. + + + + + + + + missingConferenceURI + '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. + + + + newConferenceTitle + 'Start a video conference' : Title of a popup about creation of a video conference + + + + subjectLabel + 'Subject' : Label of a text field about the subject of the chat room + + + + subjectPlaceholder + 'Give a subject' : Placeholder in a form about setting a subject + + + + subjectTooltip + 'Current subject of the Chat Room. It cannot be empty' + + Explanation about the subject of the chat room + + + askEncryption + 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. + + + + participantSelectionPlaceholder + 'Select participants' : Placeholder for a search on participant to add them in selection. + + + + participantSelectionTooltip + 'Search in your contacts or add a custom one to the chat room.' + + + + adminStatus + 'Admin' : Admin(istrator) + + word for admin status + + + removeParticipantSelection + 'Remove this participant from the selection' : Explanation about removing participant from a selection + + This is a tooltip + + + requiredField + 'Required' : Word relative to a star to explain that it is a requirement (Field form) + + + Notice diff --git a/linphone-app/assets/languages/sv.ts b/linphone-app/assets/languages/sv.ts index a0c93a410..68706bcb3 100644 --- a/linphone-app/assets/languages/sv.ts +++ b/linphone-app/assets/languages/sv.ts @@ -1543,6 +1543,90 @@ Klicka här: <a href="%1">%1</a> + + NewConference + + cancelButton + 'Cancel' : Cancel button + + + + startButton + 'Launch' : Start button + + + + missingSubject + 'You need to fill a subject.' : Tooltip to warn a user on missing field. + + + + missingParticipants + 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. + + + + + + + missingConferenceURI + '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. + + + + newConferenceTitle + 'Start a video conference' : Title of a popup about creation of a video conference + + + + subjectLabel + 'Subject' : Label of a text field about the subject of the chat room + + + + subjectPlaceholder + 'Give a subject' : Placeholder in a form about setting a subject + + + + subjectTooltip + 'Current subject of the Chat Room. It cannot be empty' + + Explanation about the subject of the chat room + + + askEncryption + 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. + + + + participantSelectionPlaceholder + 'Select participants' : Placeholder for a search on participant to add them in selection. + + + + participantSelectionTooltip + 'Search in your contacts or add a custom one to the chat room.' + + + + adminStatus + 'Admin' : Admin(istrator) + + word for admin status + + + removeParticipantSelection + 'Remove this participant from the selection' : Explanation about removing participant from a selection + + This is a tooltip + + + requiredField + 'Required' : Word relative to a star to explain that it is a requirement (Field form) + + + Notice diff --git a/linphone-app/assets/languages/tr.ts b/linphone-app/assets/languages/tr.ts index fa0949630..53f1224fe 100644 --- a/linphone-app/assets/languages/tr.ts +++ b/linphone-app/assets/languages/tr.ts @@ -1539,6 +1539,89 @@ Buraya tıklayın: <a href="%1">%1</a> Son kişiler + + NewConference + + cancelButton + 'Cancel' : Cancel button + + + + startButton + 'Launch' : Start button + + + + missingSubject + 'You need to fill a subject.' : Tooltip to warn a user on missing field. + + + + missingParticipants + 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. + + + + + + missingConferenceURI + '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. + + + + newConferenceTitle + 'Start a video conference' : Title of a popup about creation of a video conference + + + + subjectLabel + 'Subject' : Label of a text field about the subject of the chat room + + + + subjectPlaceholder + 'Give a subject' : Placeholder in a form about setting a subject + + + + subjectTooltip + 'Current subject of the Chat Room. It cannot be empty' + + Explanation about the subject of the chat room + + + askEncryption + 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. + + + + participantSelectionPlaceholder + 'Select participants' : Placeholder for a search on participant to add them in selection. + + + + participantSelectionTooltip + 'Search in your contacts or add a custom one to the chat room.' + + + + adminStatus + 'Admin' : Admin(istrator) + + word for admin status + + + removeParticipantSelection + 'Remove this participant from the selection' : Explanation about removing participant from a selection + + This is a tooltip + + + requiredField + 'Required' : Word relative to a star to explain that it is a requirement (Field form) + + + Notice diff --git a/linphone-app/assets/languages/uk.ts b/linphone-app/assets/languages/uk.ts index 9b5035f25..c41d2e99c 100644 --- a/linphone-app/assets/languages/uk.ts +++ b/linphone-app/assets/languages/uk.ts @@ -1553,6 +1553,91 @@ + + NewConference + + cancelButton + 'Cancel' : Cancel button + + + + startButton + 'Launch' : Start button + + + + missingSubject + 'You need to fill a subject.' : Tooltip to warn a user on missing field. + + + + missingParticipants + 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. + + + + + + + + missingConferenceURI + '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. + + + + newConferenceTitle + 'Start a video conference' : Title of a popup about creation of a video conference + + + + subjectLabel + 'Subject' : Label of a text field about the subject of the chat room + + + + subjectPlaceholder + 'Give a subject' : Placeholder in a form about setting a subject + + + + subjectTooltip + 'Current subject of the Chat Room. It cannot be empty' + + Explanation about the subject of the chat room + + + askEncryption + 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. + + + + participantSelectionPlaceholder + 'Select participants' : Placeholder for a search on participant to add them in selection. + + + + participantSelectionTooltip + 'Search in your contacts or add a custom one to the chat room.' + + + + adminStatus + 'Admin' : Admin(istrator) + + word for admin status + + + removeParticipantSelection + 'Remove this participant from the selection' : Explanation about removing participant from a selection + + This is a tooltip + + + requiredField + 'Required' : Word relative to a star to explain that it is a requirement (Field form) + + + Notice diff --git a/linphone-app/assets/languages/zh_CN.ts b/linphone-app/assets/languages/zh_CN.ts index 859b86dbb..7c3fee755 100644 --- a/linphone-app/assets/languages/zh_CN.ts +++ b/linphone-app/assets/languages/zh_CN.ts @@ -1533,6 +1533,89 @@ 最近联系人 + + NewConference + + askEncryption + 'Would you like to encrypt your conference?' : Ask about setting the conference as secured. + 是否加密你的聊天? + + + cancelButton + 'Cancel' : Cancel button + 取消 + + + startButton + 'Launch' : Start button + + + + missingSubject + 'You need to fill a subject.' : Tooltip to warn a user on missing field. + 你需要填写一个主题。 + + + missingParticipants + 'You need at least %1 participant.' : Tooltip to warn a user that there are not enough participants for the chat creation. + + 你需要至少%1成员 + + + + missingConferenceURI + '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. + 您需要在帐户设置中设置会议 URI 以创建基于会议的聊天室。 + + + newConferenceTitle + 'Start a video conference' : Title of a popup about creation of a video conference + + + + subjectLabel + 'Subject' : Label of a text field about the subject of the chat room + 主题 + + + subjectPlaceholder + 'Give a subject' : Placeholder in a form about setting a subject + 指定一个主题 + + + subjectTooltip + 'Current subject of the Chat Room. It cannot be empty' + 聊天室的当前主题。 它不能为空。 + Explanation about the subject of the chat room + + + participantSelectionPlaceholder + 'Select participants' : Placeholder for a search on participant to add them in selection. + 选择成员 + + + participantSelectionTooltip + 'Search in your contacts or add a custom one to the chat room.' + 搜索您的联系人或向聊天室添加自定义联系人。 + + + adminStatus + 'Admin' : Admin(istrator) + 管理员 + word for admin status + + + removeParticipantSelection + 'Remove this participant from the selection' : Explanation about removing participant from a selection + 从选择中删除此成员 + This is a tooltip + + + requiredField + 'Required' : Word relative to a star to explain that it is a requirement (Field form) + 要求 + + Notice diff --git a/linphone-app/resources.qrc b/linphone-app/resources.qrc index 61ffa4d41..b1661b964 100644 --- a/linphone-app/resources.qrc +++ b/linphone-app/resources.qrc @@ -20,6 +20,7 @@ assets/images/call_custom.svg assets/images/call_history_custom.svg assets/images/call_quality_custom.svg + assets/images/call_menu_custom.svg assets/images/call_sign_connected.svg assets/images/call_sign_ended.svg assets/images/call_sign_incoming.svg @@ -49,6 +50,7 @@ assets/images/chat_room_custom.svg assets/images/close_custom.svg assets/images/collapsed_custom.svg + assets/images/conference_custom.svg assets/images/contact_add_custom.svg assets/images/contact_card_photo_custom.svg assets/images/contact_custom.svg @@ -60,6 +62,7 @@ assets/images/current_account_status_offline.svg assets/images/current_account_status_dnd.svg assets/images/current_account_status_busy.svg + assets/images/dialpad_custom.svg assets/images/declined_incoming_call_custom.svg assets/images/declined_outgoing_call_custom.svg assets/images/delete_custom.svg @@ -103,7 +106,6 @@ assets/images/move_to_bottom_custom.svg assets/images/new_call_custom.svg assets/images/new_chat_group_custom.svg - assets/images/new_conference_custom.svg assets/images/options_custom.svg assets/images/outgoing_call_custom.svg assets/images/panel_arrow_custom.svg @@ -113,13 +115,16 @@ assets/images/panel_shown_normal.svg assets/images/panel_shown_hovered.svg assets/images/panel_shown_pressed.svg + assets/images/participants_custom.svg assets/images/pause_custom.svg assets/images/play_custom.svg assets/images/recording_sign.svg assets/images/record_custom.svg assets/images/remove_participant_custom.svg + assets/images/screen_sharing_custom.svg assets/images/screenshot_custom.svg assets/images/search_custom.svg + assets/images/schedule_custom.svg assets/images/secure_level_unsafe.svg assets/images/secure_level_1.svg assets/images/secure_level_2.svg @@ -178,6 +183,7 @@ ui/modules/Common/Form/ListForm.qml ui/modules/Common/Form/ListItemSelector.js ui/modules/Common/Form/ListItemSelector.qml + ui/modules/Common/Form/Mosaic.qml ui/modules/Common/Form/MouseArea.qml ui/modules/Common/Form/Placements/FormEmptyLine.qml ui/modules/Common/Form/Placements/FormGroup.qml @@ -212,6 +218,8 @@ ui/modules/Common/Misc/Borders.qml ui/modules/Common/Misc/ForceScrollBar.qml ui/modules/Common/Misc/Paned.qml + ui/modules/Common/Picker/DatePicker.qml + ui/modules/Common/Picker/TimePicker.qml ui/modules/Common/Popup/DesktopPopup.qml ui/modules/Common/Popup/Popup.qml ui/modules/Common/Popup/PopupShadow.qml @@ -254,6 +262,8 @@ ui/modules/Common/Styles/Menus/MenuStyle.qml ui/modules/Common/Styles/Misc/ForceScrollBarStyle.qml ui/modules/Common/Styles/Misc/PanedStyle.qml + ui/modules/Common/Styles/Picker/DatePickerStyle.qml + ui/modules/Common/Styles/Picker/TimePickerStyle.qml ui/modules/Common/Styles/Popup/PopupStyle.qml ui/modules/Common/Styles/qmldir ui/modules/Common/Styles/Tooltip/TooltipStyle.qml @@ -371,6 +381,7 @@ ui/views/App/Calls/CallsWindow.js ui/views/App/Calls/CallsWindow.qml ui/views/App/Calls/Conference.qml + ui/views/App/Calls/VideoConference.qml ui/views/App/Calls/Dialogs/CallSipAddress.qml ui/views/App/Calls/Dialogs/CallTransfer.qml ui/views/App/Calls/Dialogs/ConferenceManager.qml @@ -396,6 +407,7 @@ ui/views/App/Main/Assistant/UseAppSipAccountWithPhoneNumber.qml ui/views/App/Main/Assistant/UseAppSipAccountWithUsername.qml ui/views/App/Main/Assistant/UseOtherSipAccount.qml + ui/views/App/Main/Conferences.qml ui/views/App/Main/ContactEdit.js ui/views/App/Main/ContactEdit.qml ui/views/App/Main/Contacts.qml @@ -410,6 +422,7 @@ ui/views/App/Main/Dialogs/ManageAccount.js ui/views/App/Main/Dialogs/ManageAccounts.qml ui/views/App/Main/Dialogs/NewChatRoom.qml + ui/views/App/Main/Dialogs/NewConference.qml ui/views/App/Main/Dialogs/ParticipantsDevices.qml ui/views/App/Main/Home.qml ui/views/App/Main/HistoryView.qml @@ -441,6 +454,7 @@ ui/views/App/Styles/Calls/CallFullscreenStyle.qml ui/views/App/Styles/Calls/CallsWindowStyle.qml ui/views/App/Styles/Calls/ConferenceStyle.qml + ui/views/App/Styles/Calls/VideoConferenceStyle.qml ui/views/App/Styles/Calls/Dialogs/CallSipAddressStyle.qml ui/views/App/Styles/Calls/Dialogs/CallTransferStyle.qml ui/views/App/Styles/Calls/Dialogs/ConferenceManagerStyle.qml @@ -452,6 +466,7 @@ ui/views/App/Styles/Main/Assistant/CreateAppSipAccountStyle.qml ui/views/App/Styles/Main/AssistantStyle.qml ui/views/App/Styles/Main/Assistant/UseAppSipAccountStyle.qml + ui/views/App/Styles/Main/ConferencesStyle.qml ui/views/App/Styles/Main/ContactEditStyle.qml ui/views/App/Styles/Main/ContactsStyle.qml ui/views/App/Styles/Main/ConversationStyle.qml @@ -461,6 +476,7 @@ ui/views/App/Styles/Main/Dialogs/InfoChatRoomStyle.qml ui/views/App/Styles/Main/Dialogs/InfoEncryptionStyle.qml ui/views/App/Styles/Main/Dialogs/NewChatRoomStyle.qml + ui/views/App/Styles/Main/Dialogs/NewConferenceStyle.qml ui/views/App/Styles/Main/Dialogs/ManageAccountsStyle.qml ui/views/App/Styles/Main/Dialogs/ParticipantsDevicesStyle.qml ui/views/App/Styles/Main/HomeStyle.qml diff --git a/linphone-app/src/app/App.cpp b/linphone-app/src/app/App.cpp index bfa72c94d..4d44a7337 100644 --- a/linphone-app/src/app/App.cpp +++ b/linphone-app/src/app/App.cpp @@ -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>(); qRegisterMetaType>(); qRegisterMetaType>(); + qRegisterMetaType>(); //qRegisterMetaType>(); LinphoneEnums::registerMetaTypes(); @@ -621,7 +625,9 @@ void App::registerTypes () { registerType("CameraPreview"); registerType("ChatRoomProxyModel"); registerType("ConferenceHelperModel"); - registerType("ConferenceModel"); + registerType("ConferenceProxyModel"); + registerType("ConferenceInfoModel"); + registerType("ConferenceInfoProxyModel"); registerType("ContactsListProxyModel"); registerType("ContactsImporterListProxyModel"); registerType("ContentProxyModel"); @@ -659,6 +665,8 @@ void App::registerTypes () { registerUncreatableType("ColorModel"); registerUncreatableType("ImageModel"); registerUncreatableType("ConferenceAddModel"); + registerUncreatableType("ConferenceModel"); + registerUncreatableType("ConferenceInfoListModel"); registerUncreatableType("ContactModel"); registerUncreatableType("ContactsImporterModel"); registerUncreatableType("ContentModel"); diff --git a/linphone-app/src/components/Components.hpp b/linphone-app/src/components/Components.hpp index 8e8f4f3d0..f518166ac 100644 --- a/linphone-app/src/components/Components.hpp +++ b/linphone-app/src/components/Components.hpp @@ -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" diff --git a/linphone-app/src/components/call/CallModel.cpp b/linphone-app/src/components/call/CallModel.cpp index a76121298..2c92f8ae2 100644 --- a/linphone-app/src/components/call/CallModel.cpp +++ b/linphone-app/src/components/call/CallModel.cpp @@ -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 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 call){ QObject::connect(mSearch.get(), SIGNAL(searchReceived(std::list> )), this, SLOT(searchReceived(std::list>))); mMagicSearch->addListener(mSearch); - mRemoteAddress = mCall->getRemoteAddress()->clone(); + if(mCall) { + mRemoteAddress = mCall->getRemoteAddress()->clone(); + if(mCall->getConference()) + mConferenceModel = std::make_shared(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 CallModel::getConferenceModel() const{ + return mConferenceModel; +} + +bool CallModel::isConference () const{ + return mCall->getConference() != nullptr; +} + // ----------------------------------------------------------------------------- void CallModel::setRecordFile (const shared_ptr &callParams) { callParams->setRecordFile(Utils::appStringToCoreString( @@ -199,7 +214,7 @@ void CallModel::updateStats (const shared_ptr &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 params = CoreManager::getInstance()->getCore()->createCallParams(mCall); - params->enableVideo(true); - - mCall->acceptUpdate(params); + if(mCall) { + shared_ptr params = CoreManager::getInstance()->getCore()->createCallParams(mCall); + params->enableVideo(true); + mCall->acceptUpdate(params); + } } void CallModel::rejectVideoRequest () { - shared_ptr params = CoreManager::getInstance()->getCore()->createCallParams(mCall); - params->enableVideo(false); + if(mCall) { + shared_ptr 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 &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 core = coreManager->getCore(); - shared_ptr params = core->createCallParams(mCall); - params->enableVideo(withVideo); - setRecordFile(params); + if(mCall) { + shared_ptr 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 params = mCall->getCurrentParams(); - return params && params->videoEnabled() && getStatus() == CallStatusConnected; + if(mCall){ + shared_ptr 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 params = core->createCallParams(mCall); + params->enableVideo(status); + + mCall->update(params); } - - if (status == getVideoEnabled()) - return; - - shared_ptr 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 } 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 core = CoreManager::getInstance()->getCore(); - std::shared_ptr params = core->createDefaultChatRoomParams(); - std::list> participants; + if(mCall){ + ChatRoomModel * model = getChatRoomModel(); - auto chatRoom = core->searchChatRoom(params, mCall->getCallLog()->getLocalAddress() - , mCall->getRemoteAddress() - , participants); - std::shared_ptr 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 core = CoreManager::getInstance()->getCore(); + std::shared_ptr params = core->createDefaultChatRoomParams(); + std::list> participants; + + auto chatRoom = core->searchChatRoom(params, mCall->getCallLog()->getLocalAddress() + , mCall->getRemoteAddress() + , participants); + std::shared_ptr 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 CallModel::getRemoteAddress()const{ // ----------------------------------------------------------------------------- CallModel::CallEncryption CallModel::getEncryption () const { - return static_cast(mCall->getCurrentParams()->getMediaEncryption()); + if(mCall) + return static_cast(mCall->getCurrentParams()->getMediaEncryption()); + else + return CallEncryptionNone; } bool CallModel::isSecured () const { - shared_ptr 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 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 &callStats, QVariantList &statsList) { - shared_ptr params = mCall->getCurrentParams(); - shared_ptr 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(callStats->getSenderLossRate()))); - statsList << createStat(tr("callStatsReceiverLossRate"), QStringLiteral("%1 %").arg(static_cast(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(params->getReceivedFramerate()))); - statsList << createStat(tr("callStatsSentFramerate"), QStringLiteral("%1 FPS").arg(static_cast(params->getSentFramerate()))); - } break; - - default: - break; + if(mCall){ + shared_ptr params = mCall->getCurrentParams(); + shared_ptr 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(callStats->getSenderLossRate()))); + statsList << createStat(tr("callStatsReceiverLossRate"), QStringLiteral("%1 %").arg(static_cast(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(params->getReceivedFramerate()))); + statsList << createStat(tr("callStatsSentFramerate"), QStringLiteral("%1 FPS").arg(static_cast(params->getSentFramerate()))); + } break; + + default: + break; + } } } diff --git a/linphone-app/src/components/call/CallModel.hpp b/linphone-app/src/components/call/CallModel.hpp index ad14da3be..791b7bd88 100644 --- a/linphone-app/src/components/call/CallModel.hpp +++ b/linphone-app/src/components/call/CallModel.hpp @@ -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 getConferenceModel() const; bool isInConference () const { return mIsInConference; } + bool isConference () const; void setRecordFile (const std::shared_ptr &callParams); static void setRecordFile (const std::shared_ptr &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 mSearch; QString mTransferAddress; + std::shared_ptr mConferenceModel; }; #endif // CALL_MODEL_H_ diff --git a/linphone-app/src/components/calls/CallsListModel.cpp b/linphone-app/src/components/calls/CallsListModel.cpp index b7fe3b51c..1d21cce80 100644 --- a/linphone-app/src/components/calls/CallsListModel.cpp +++ b/linphone-app/src/components/calls/CallsListModel.cpp @@ -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 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 core = CoreManager::getInstance()->getCore(); + std::shared_ptr conference; + QList< std::shared_ptr> admins; + std::shared_ptr timeline; + auto timelineList = CoreManager::getInstance()->getTimelineListModel(); + qInfo() << "Conference creation of " << conferenceInfo->getSubject() << " at " << securityLevel << " security";// and with " << conferenceInfo->getConferenceInfo()->getParticipants().size(); + + std::shared_ptr params = core->createConferenceParams(); + std::list > participants = conferenceInfo->getConferenceInfo()->getParticipants(); + std::shared_ptr localAddress; + + /* + for(auto p : participants){ + ParticipantModel* participant = p.value(); + std::shared_ptr 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(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 &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 &call) { CallModel *callModel; diff --git a/linphone-app/src/components/calls/CallsListModel.hpp b/linphone-app/src/components/calls/CallsListModel.hpp index 0d473c5cc..1ca7aa800 100644 --- a/linphone-app/src/components/calls/CallsListModel.hpp +++ b/linphone-app/src/components/calls/CallsListModel.hpp @@ -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 &headers = {}) const; Q_INVOKABLE void launchSecureAudioCall (const QString &sipAddress, LinphoneEnums::MediaEncryption encryption, const QHash &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 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 &call, linphone::Call::State state); void addCall (const std::shared_ptr &call); + void addDummyCall (); void removeCall (const std::shared_ptr &call); void removeCallCb (CallModel *callModel); QList mList; + QList> mConferences; std::shared_ptr mCoreHandlers; }; diff --git a/linphone-app/src/components/conference/ConferenceModel.cpp b/linphone-app/src/components/conference/ConferenceModel.cpp index dff2d0d7f..c7b993d5d 100644 --- a/linphone-app/src/components/conference/ConferenceModel.cpp +++ b/linphone-app/src/components/conference/ConferenceModel.cpp @@ -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 . */ -#include -#include +#include "ConferenceModel.hpp" + +#include +#include +#include +#include #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(); - return callModel->getCall()->getParams()->getLocalConferenceMode() || callModel->getCall()->getCurrentParams()->getLocalConferenceMode(); -} -// ----------------------------------------------------------------------------- - -void ConferenceModel::terminate () { - shared_ptr 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 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 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 ConferenceModel::getConference()const{ + return mConference; } diff --git a/linphone-app/src/components/conference/ConferenceModel.hpp b/linphone-app/src/components/conference/ConferenceModel.hpp index 67096cec4..add828892 100644 --- a/linphone-app/src/components/conference/ConferenceModel.hpp +++ b/linphone-app/src/components/conference/ConferenceModel.hpp @@ -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 +#include // ============================================================================= +#include +#include +#include -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 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 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 mConference; }; +Q_DECLARE_METATYPE(std::shared_ptr) -#endif // CONFERENCE_MODEL_H_ +#endif diff --git a/linphone-app/src/components/conference/ConferenceProxyModel.cpp b/linphone-app/src/components/conference/ConferenceProxyModel.cpp new file mode 100644 index 000000000..7448ea665 --- /dev/null +++ b/linphone-app/src/components/conference/ConferenceProxyModel.cpp @@ -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 . + */ + +#include +#include + +#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(); + return callModel->getCall()->getParams()->getLocalConferenceMode() || callModel->getCall()->getCurrentParams()->getLocalConferenceMode(); +} +// ----------------------------------------------------------------------------- + +void ConferenceProxyModel::terminate () { + shared_ptr 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 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(); +} diff --git a/linphone-app/src/components/conference/ConferenceProxyModel.hpp b/linphone-app/src/components/conference/ConferenceProxyModel.hpp new file mode 100644 index 000000000..e1eb18308 --- /dev/null +++ b/linphone-app/src/components/conference/ConferenceProxyModel.hpp @@ -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 . + */ + +#ifndef CONFERENCE_PROXY_MODEL_H_ +#define CONFERENCE_PROXY_MODEL_H_ + +#include + +// ============================================================================= + +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_ diff --git a/linphone-app/src/components/conferenceInfo/ConferenceInfoListModel.cpp b/linphone-app/src/components/conferenceInfo/ConferenceInfoListModel.cpp new file mode 100644 index 000000000..be7e8f007 --- /dev/null +++ b/linphone-app/src/components/conferenceInfo/ConferenceInfoListModel.cpp @@ -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 . + */ + +#include +#include +#include + +#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 ConferenceInfoListModel::roleNames () const { + QHash 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; +} + +// ----------------------------------------------------------------------------- diff --git a/linphone-app/src/components/conferenceInfo/ConferenceInfoListModel.hpp b/linphone-app/src/components/conferenceInfo/ConferenceInfoListModel.hpp new file mode 100644 index 000000000..395b42c6e --- /dev/null +++ b/linphone-app/src/components/conferenceInfo/ConferenceInfoListModel.hpp @@ -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 . + */ + +#ifndef _CONFERENCE_INFO_LIST_MODEL_H_ +#define _CONFERENCE_INFO_LIST_MODEL_H_ + +#include +#include + +// ============================================================================= + +class ConferenceInfoModel; + +class ConferenceInfoListModel : public QAbstractListModel { + Q_OBJECT + +public: + ConferenceInfoListModel (QObject *parent = Q_NULLPTR); + + int rowCount (const QModelIndex &index = QModelIndex()) const override; + + QHash 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> mList; + +}; + +#endif diff --git a/linphone-app/src/components/conferenceInfo/ConferenceInfoModel.cpp b/linphone-app/src/components/conferenceInfo/ConferenceInfoModel.cpp new file mode 100644 index 000000000..cf2933449 --- /dev/null +++ b/linphone-app/src/components/conferenceInfo/ConferenceInfoModel.cpp @@ -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 . + */ + +#include "ConferenceInfoModel.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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::create(std::shared_ptr conferenceInfo){ + std::shared_ptr model = std::make_shared(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 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 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()); +} diff --git a/linphone-app/src/components/conferenceInfo/ConferenceInfoModel.hpp b/linphone-app/src/components/conferenceInfo/ConferenceInfoModel.hpp new file mode 100644 index 000000000..9046dab2a --- /dev/null +++ b/linphone-app/src/components/conferenceInfo/ConferenceInfoModel.hpp @@ -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 . + */ + +#ifndef CONFERENCE_INFO_MODEL_H_ +#define CONFERENCE_INFO_MODEL_H_ + +#include +#include +#include + +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 create(std::shared_ptr conferenceInfo); + ConferenceInfoModel (QObject * parent = nullptr); + ConferenceInfoModel (std::shared_ptr conferenceInfo, QObject * parent = nullptr); + ~ConferenceInfoModel (); + std::shared_ptr 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 mConferenceInfo; + +}; + +Q_DECLARE_METATYPE(std::shared_ptr) + +#endif diff --git a/linphone-app/src/components/conferenceInfo/ConferenceInfoProxyModel.cpp b/linphone-app/src/components/conferenceInfo/ConferenceInfoProxyModel.cpp new file mode 100644 index 000000000..aa347ef67 --- /dev/null +++ b/linphone-app/src/components/conferenceInfo/ConferenceInfoProxyModel.cpp @@ -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 . + */ + +#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; +} diff --git a/linphone-app/src/components/conferenceInfo/ConferenceInfoProxyModel.hpp b/linphone-app/src/components/conferenceInfo/ConferenceInfoProxyModel.hpp new file mode 100644 index 000000000..f687a3299 --- /dev/null +++ b/linphone-app/src/components/conferenceInfo/ConferenceInfoProxyModel.hpp @@ -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 . + */ + +#ifndef CONFERENCE_INFO_PROXY_MODEL_H_ +#define CONFERENCE_INFO_PROXY_MODEL_H_ + +#include + +#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 mConferenceInfoModel; +}; + +#endif diff --git a/linphone-app/src/components/core/CoreHandlers.cpp b/linphone-app/src/components/core/CoreHandlers.cpp index 8b078a85f..19787d21c 100644 --- a/linphone-app/src/components/core/CoreHandlers.cpp +++ b/linphone-app/src/components/core/CoreHandlers.cpp @@ -323,3 +323,21 @@ void CoreHandlers::onEcCalibrationResult( ) { emit ecCalibrationResult(status, delayMs); } + +//------------------------------ CONFERENCE INFO + +void CoreHandlers::onConferenceInfoCreated(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo){ + qWarning() << "onConferenceInfoCreated"; +} + +void CoreHandlers::onConferenceInfoOnSent(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo){ + qWarning() << "onConferenceInfoOnSent"; +} + +void CoreHandlers::onConferenceInfoParticipantSent(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo, const std::shared_ptr & participant){ + qWarning() << "onConferenceInfoParticipantSent"; +} + +void CoreHandlers::onConferenceInfoParticipantError(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo, const std::shared_ptr & participant, linphone::ConferenceInfoError error){ + qWarning() << "onConferenceInfoParticipantError"; +} \ No newline at end of file diff --git a/linphone-app/src/components/core/CoreHandlers.hpp b/linphone-app/src/components/core/CoreHandlers.hpp index 9dc52ceaa..05c32be87 100644 --- a/linphone-app/src/components/core/CoreHandlers.hpp +++ b/linphone-app/src/components/core/CoreHandlers.hpp @@ -60,7 +60,6 @@ signals: void setLastRemoteProvisioningState(const linphone::ConfiguringState &state); private: - // --------------------------------------------------------------------------- // Linphone callbacks. // --------------------------------------------------------------------------- @@ -159,8 +158,13 @@ private: const std::shared_ptr &core, const std::shared_ptr &linphoneFriend ) override; - - //void onRegistrationStateChanged ( + + void onRegistrationStateChanged ( + const std::shared_ptr &core, + const std::shared_ptr &proxyConfig, + linphone::RegistrationState state, + const std::string &message + ) override; void onTransferStateChanged ( const std::shared_ptr &core, @@ -181,6 +185,13 @@ private: int delayMs ) override; + // Conference Info + virtual void onConferenceInfoCreated(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo); + virtual void onConferenceInfoOnSent(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo); + virtual void onConferenceInfoParticipantSent(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo, const std::shared_ptr & participant); + virtual void onConferenceInfoParticipantError(const std::shared_ptr & core, const std::shared_ptr & conferenceInfo, const std::shared_ptr & participant, linphone::ConferenceInfoError error); + + // --------------------------------------------------------------------------- }; diff --git a/linphone-app/src/components/other/colors/ColorListModel.hpp b/linphone-app/src/components/other/colors/ColorListModel.hpp index 4529d9597..a2a192d41 100644 --- a/linphone-app/src/components/other/colors/ColorListModel.hpp +++ b/linphone-app/src/components/other/colors/ColorListModel.hpp @@ -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 // diff --git a/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp b/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp index f315d329b..6588735fd 100644 --- a/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp +++ b/linphone-app/src/components/participant/ParticipantDeviceListModel.cpp @@ -38,6 +38,17 @@ ParticipantDeviceListModel::ParticipantDeviceListModel (std::shared_ptrisConference()) { + std::list> devices = callModel->getConferenceModel()->getConference()->getParticipantDeviceList(); + for(auto device : devices){ + auto deviceModel = std::make_shared(device); + connect(this, &ParticipantDeviceListModel::securityLevelChanged, deviceModel.get(), &ParticipantDeviceModel::onSecurityLevelChanged); + mList << deviceModel; + } + } +} + int ParticipantDeviceListModel::rowCount (const QModelIndex &index) const{ return mList.count(); } diff --git a/linphone-app/src/components/participant/ParticipantDeviceListModel.hpp b/linphone-app/src/components/participant/ParticipantDeviceListModel.hpp index 41f1d42fb..818e4bc13 100644 --- a/linphone-app/src/components/participant/ParticipantDeviceListModel.hpp +++ b/linphone-app/src/components/participant/ParticipantDeviceListModel.hpp @@ -29,6 +29,7 @@ #include #include +class CallModel; class ParticipantDeviceModel; class ParticipantDeviceListModel : public QAbstractListModel { @@ -36,6 +37,7 @@ class ParticipantDeviceListModel : public QAbstractListModel { public: ParticipantDeviceListModel (std::shared_ptr participant, QObject *parent = nullptr); + ParticipantDeviceListModel (CallModel * callModel, QObject *parent = nullptr); int rowCount (const QModelIndex &index = QModelIndex()) const override; int count(); diff --git a/linphone-app/src/components/participant/ParticipantDeviceProxyModel.cpp b/linphone-app/src/components/participant/ParticipantDeviceProxyModel.cpp index fc4877d11..9dbdefc74 100644 --- a/linphone-app/src/components/participant/ParticipantDeviceProxyModel.cpp +++ b/linphone-app/src/components/participant/ParticipantDeviceProxyModel.cpp @@ -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()); } \ No newline at end of file diff --git a/linphone-app/src/components/participant/ParticipantDeviceProxyModel.hpp b/linphone-app/src/components/participant/ParticipantDeviceProxyModel.hpp index 404a673fb..7f92e1260 100644 --- a/linphone-app/src/components/participant/ParticipantDeviceProxyModel.hpp +++ b/linphone-app/src/components/participant/ParticipantDeviceProxyModel.hpp @@ -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 mDevices; + CallModel * mCallModel; }; diff --git a/linphone-app/src/components/participant/ParticipantListModel.cpp b/linphone-app/src/components/participant/ParticipantListModel.cpp index 9d9c988f9..a318cd411 100644 --- a/linphone-app/src/components/participant/ParticipantListModel.cpp +++ b/linphone-app/src/components/participant/ParticipantListModel.cpp @@ -70,6 +70,14 @@ int ParticipantListModel::getCount() const{ return mParticipants.size(); } +std::list> ParticipantListModel::getParticipants()const{ + std::list> participants; + for(auto participant : mParticipants){ + participants.push_back(Utils::interpretUrl(participant->getSipAddress())); + } + return participants; +} + QString ParticipantListModel::addressesToString()const{ QStringList txt; for(auto participant : mParticipants){ diff --git a/linphone-app/src/components/participant/ParticipantListModel.hpp b/linphone-app/src/components/participant/ParticipantListModel.hpp index ce438d42e..1c033f59d 100644 --- a/linphone-app/src/components/participant/ParticipantListModel.hpp +++ b/linphone-app/src/components/participant/ParticipantListModel.hpp @@ -56,6 +56,7 @@ public: Q_INVOKABLE void remove (ParticipantModel *importer); Q_INVOKABLE ChatRoomModel* getChatRoomModel() const; int getCount() const; + std::list> getParticipants()const; Q_INVOKABLE QString addressesToString()const; Q_INVOKABLE QString displayNamesToString()const; diff --git a/linphone-app/src/components/participant/ParticipantProxyModel.cpp b/linphone-app/src/components/participant/ParticipantProxyModel.cpp index 9a7d8a5e1..4aa07211e 100644 --- a/linphone-app/src/components/participant/ParticipantProxyModel.cpp +++ b/linphone-app/src/components/participant/ParticipantProxyModel.cpp @@ -45,6 +45,10 @@ ChatRoomModel *ParticipantProxyModel::getChatRoomModel() const{ return mChatRoomModel; } +ParticipantListModel * ParticipantProxyModel::getParticipantListModel() const{ + return dynamic_cast(sourceModel()); +} + QStringList ParticipantProxyModel::getSipAddresses() const{ QStringList participants; ParticipantListModel * list = dynamic_cast(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(); diff --git a/linphone-app/src/components/participant/ParticipantProxyModel.hpp b/linphone-app/src/components/participant/ParticipantProxyModel.hpp index ab44b52b4..8a042b3f4 100644 --- a/linphone-app/src/components/participant/ParticipantProxyModel.hpp +++ b/linphone-app/src/components/participant/ParticipantProxyModel.hpp @@ -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); diff --git a/linphone-app/src/components/timeline/TimelineListModel.cpp b/linphone-app/src/components/timeline/TimelineListModel.cpp index 47b35acaf..b7af65897 100644 --- a/linphone-app/src/components/timeline/TimelineListModel.cpp +++ b/linphone-app/src/components/timeline/TimelineListModel.cpp @@ -152,7 +152,26 @@ std::shared_ptr TimelineListModel::getTimeline(std::shared_ptr
  • TimelineListModel::getTimeline(std::shared_ptr 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 model = TimelineModel::create(conference); + //std::shared_ptr model = std::make_shared(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 sortedData; diff --git a/linphone-app/src/components/timeline/TimelineListModel.hpp b/linphone-app/src/components/timeline/TimelineListModel.hpp index 2e422e226..32de49cee 100644 --- a/linphone-app/src/components/timeline/TimelineListModel.hpp +++ b/linphone-app/src/components/timeline/TimelineListModel.hpp @@ -40,6 +40,7 @@ public: void selectAll(const bool& selected); TimelineModel * getAt(const int& index); std::shared_ptr getTimeline(std::shared_ptr chatRoom, const bool &create); + //std::shared_ptr getTimeline(std::shared_ptr chatRoom, const bool &create); Q_INVOKABLE QVariantList getLastChatRooms(const int& maxCount) const; std::shared_ptr getChatRoomModel(std::shared_ptr chatRoom, const bool &create); std::shared_ptr getChatRoomModel(ChatRoomModel * chatRoom); diff --git a/linphone-app/src/utils/Constants.hpp b/linphone-app/src/utils/Constants.hpp index 3537dddbe..9c2bd4127 100644 --- a/linphone-app/src/utils/Constants.hpp +++ b/linphone-app/src/utils/Constants.hpp @@ -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"; diff --git a/linphone-app/src/utils/Utils.cpp b/linphone-app/src/utils/Utils.cpp index e8b2390ba..c89bc7667 100644 --- a/linphone-app/src/utils/Utils.cpp +++ b/linphone-app/src/utils/Utils.cpp @@ -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); diff --git a/linphone-app/src/utils/Utils.hpp b/linphone-app/src/utils/Utils.hpp index 4accdff23..db10a6179 100644 --- a/linphone-app/src/utils/Utils.hpp +++ b/linphone-app/src/utils/Utils.hpp @@ -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); diff --git a/linphone-app/ui/modules/Common/Dialog/DialogPlus.qml b/linphone-app/ui/modules/Common/Dialog/DialogPlus.qml index d916ec44f..de5efe688 100644 --- a/linphone-app/ui/modules/Common/Dialog/DialogPlus.qml +++ b/linphone-app/ui/modules/Common/Dialog/DialogPlus.qml @@ -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) diff --git a/linphone-app/ui/modules/Common/Form/ActionButton.qml b/linphone-app/ui/modules/Common/Form/ActionButton.qml index 1d456b5cb..04d5aaad5 100644 --- a/linphone-app/ui/modules/Common/Form/ActionButton.qml +++ b/linphone-app/ui/modules/Common/Form/ActionButton.qml @@ -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 + } } } diff --git a/linphone-app/ui/modules/Common/Form/Fields/TextAreaField.qml b/linphone-app/ui/modules/Common/Form/Fields/TextAreaField.qml index 792e9b117..4663413f2 100644 --- a/linphone-app/ui/modules/Common/Form/Fields/TextAreaField.qml +++ b/linphone-app/ui/modules/Common/Form/Fields/TextAreaField.qml @@ -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 + } + } } diff --git a/linphone-app/ui/modules/Common/Form/Mosaic.qml b/linphone-app/ui/modules/Common/Form/Mosaic.qml new file mode 100644 index 000000000..8eaf61891 --- /dev/null +++ b/linphone-app/ui/modules/Common/Form/Mosaic.qml @@ -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) + }*/ + //} + +} \ No newline at end of file diff --git a/linphone-app/ui/modules/Common/Misc/Paned.qml b/linphone-app/ui/modules/Common/Misc/Paned.qml index 37f8c6995..8c0de6359 100644 --- a/linphone-app/ui/modules/Common/Misc/Paned.qml +++ b/linphone-app/ui/modules/Common/Misc/Paned.qml @@ -258,6 +258,7 @@ Item { height: parent.height visible: _isVisible(Qt.LeftEdge) + onVisibleChanged: console.log(visible) } MouseArea { diff --git a/linphone-app/ui/modules/Common/Picker/DatePicker.qml b/linphone-app/ui/modules/Common/Picker/DatePicker.qml new file mode 100644 index 000000000..7001df748 --- /dev/null +++ b/linphone-app/ui/modules/Common/Picker/DatePicker.qml @@ -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) + } +} \ No newline at end of file diff --git a/linphone-app/ui/modules/Common/Picker/TimePicker.qml b/linphone-app/ui/modules/Common/Picker/TimePicker.qml new file mode 100644 index 000000000..8a52c672c --- /dev/null +++ b/linphone-app/ui/modules/Common/Picker/TimePicker.qml @@ -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 + + } +} \ No newline at end of file diff --git a/linphone-app/ui/modules/Common/Styles/Picker/DatePickerStyle.qml b/linphone-app/ui/modules/Common/Styles/Picker/DatePickerStyle.qml new file mode 100644 index 000000000..4b2223cd5 --- /dev/null +++ b/linphone-app/ui/modules/Common/Styles/Picker/DatePickerStyle.qml @@ -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 + } +} diff --git a/linphone-app/ui/modules/Common/Styles/Picker/TimePickerStyle.qml b/linphone-app/ui/modules/Common/Styles/Picker/TimePickerStyle.qml new file mode 100644 index 000000000..ff60acd81 --- /dev/null +++ b/linphone-app/ui/modules/Common/Styles/Picker/TimePickerStyle.qml @@ -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 + +} diff --git a/linphone-app/ui/modules/Common/Styles/qmldir b/linphone-app/ui/modules/Common/Styles/qmldir index db6a3eb2e..b55f415d0 100644 --- a/linphone-app/ui/modules/Common/Styles/qmldir +++ b/linphone-app/ui/modules/Common/Styles/qmldir @@ -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 diff --git a/linphone-app/ui/modules/Common/qmldir b/linphone-app/ui/modules/Common/qmldir index da4f8190b..71ad8f096 100644 --- a/linphone-app/ui/modules/Common/qmldir +++ b/linphone-app/ui/modules/Common/qmldir @@ -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 diff --git a/linphone-app/ui/modules/Linphone/SmartSearchBar/SmartSearchBar.qml b/linphone-app/ui/modules/Linphone/SmartSearchBar/SmartSearchBar.qml index 610d6ab95..367be8c72 100644 --- a/linphone-app/ui/modules/Linphone/SmartSearchBar/SmartSearchBar.qml +++ b/linphone-app/ui/modules/Linphone/SmartSearchBar/SmartSearchBar.qml @@ -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, diff --git a/linphone-app/ui/modules/Linphone/View/SipAddressesView.qml b/linphone-app/ui/modules/Linphone/View/SipAddressesView.qml index 42723f659..326e477d8 100644 --- a/linphone-app/ui/modules/Linphone/View/SipAddressesView.qml +++ b/linphone-app/ui/modules/Linphone/View/SipAddressesView.qml @@ -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 diff --git a/linphone-app/ui/views/App/Calls/CallsWindow.js b/linphone-app/ui/views/App/Calls/CallsWindow.js index d8210f3e6..6cf3cac7e 100644 --- a/linphone-app/ui/views/App/Calls/CallsWindow.js +++ b/linphone-app/ui/views/App/Calls/CallsWindow.js @@ -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 } diff --git a/linphone-app/ui/views/App/Calls/CallsWindow.qml b/linphone-app/ui/views/App/Calls/CallsWindow.qml index 7c1e2c315..35d8b3080 100644 --- a/linphone-app/ui/views/App/Calls/CallsWindow.qml +++ b/linphone-app/ui/views/App/Calls/CallsWindow.qml @@ -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 { diff --git a/linphone-app/ui/views/App/Calls/VideoConference.qml b/linphone-app/ui/views/App/Calls/VideoConference.qml new file mode 100644 index 000000000..587944e53 --- /dev/null +++ b/linphone-app/ui/views/App/Calls/VideoConference.qml @@ -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 + } + } + } + } +} diff --git a/linphone-app/ui/views/App/Main/Conferences.qml b/linphone-app/ui/views/App/Main/Conferences.qml new file mode 100644 index 000000000..f5e5e37e0 --- /dev/null +++ b/linphone-app/ui/views/App/Main/Conferences.qml @@ -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 + } + } + } + } + } + + + } + } +} diff --git a/linphone-app/ui/views/App/Main/Dialogs/NewConference.qml b/linphone-app/ui/views/App/Main/Dialogs/NewConference.qml new file mode 100644 index 000000000..ee00b8cc3 --- /dev/null +++ b/linphone-app/ui/views/App/Main/Dialogs/NewConference.qml @@ -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') +'*' + 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 : '* '+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() + } + } + } + } + } +} \ No newline at end of file diff --git a/linphone-app/ui/views/App/Main/MainWindow.js b/linphone-app/ui/views/App/Main/MainWindow.js index acf2f46dc..604b55be4 100644 --- a/linphone-app/ui/views/App/Main/MainWindow.js +++ b/linphone-app/ui/views/App/Main/MainWindow.js @@ -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() } } diff --git a/linphone-app/ui/views/App/Main/MainWindow.qml b/linphone-app/ui/views/App/Main/MainWindow.qml index 0265c061a..580d4f4dd 100644 --- a/linphone-app/ui/views/App/Main/MainWindow.qml +++ b/linphone-app/ui/views/App/Main/MainWindow.qml @@ -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. diff --git a/linphone-app/ui/views/App/Styles/Calls/CallsWindowStyle.qml b/linphone-app/ui/views/App/Styles/Calls/CallsWindowStyle.qml index 13cd5bee6..c98dcc121 100644 --- a/linphone-app/ui/views/App/Styles/Calls/CallsWindowStyle.qml +++ b/linphone-app/ui/views/App/Styles/Calls/CallsWindowStyle.qml @@ -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 diff --git a/linphone-app/ui/views/App/Styles/Calls/VideoConferenceStyle.qml b/linphone-app/ui/views/App/Styles/Calls/VideoConferenceStyle.qml new file mode 100644 index 000000000..2b353a8c5 --- /dev/null +++ b/linphone-app/ui/views/App/Styles/Calls/VideoConferenceStyle.qml @@ -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 + } + } +} diff --git a/linphone-app/ui/views/App/Styles/Main/ConferencesStyle.qml b/linphone-app/ui/views/App/Styles/Main/ConferencesStyle.qml new file mode 100644 index 000000000..9adfc73ca --- /dev/null +++ b/linphone-app/ui/views/App/Styles/Main/ConferencesStyle.qml @@ -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 + } +} diff --git a/linphone-app/ui/views/App/Styles/Main/Dialogs/NewConferenceStyle.qml b/linphone-app/ui/views/App/Styles/Main/Dialogs/NewConferenceStyle.qml new file mode 100644 index 000000000..5a50b34bf --- /dev/null +++ b/linphone-app/ui/views/App/Styles/Main/Dialogs/NewConferenceStyle.qml @@ -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 + } +} \ No newline at end of file diff --git a/linphone-app/ui/views/App/Styles/Main/MainWindowStyle.qml b/linphone-app/ui/views/App/Styles/Main/MainWindowStyle.qml index 6d4e1befa..349644f25 100644 --- a/linphone-app/ui/views/App/Styles/Main/MainWindowStyle.qml +++ b/linphone-app/ui/views/App/Styles/Main/MainWindowStyle.qml @@ -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 diff --git a/linphone-app/ui/views/App/Styles/qmldir b/linphone-app/ui/views/App/Styles/qmldir index 9e0dd7975..834213e25 100644 --- a/linphone-app/ui/views/App/Styles/qmldir +++ b/linphone-app/ui/views/App/Styles/qmldir @@ -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