Add a simple log viewer inside the application.

This commit is contained in:
Julien Wadel 2022-06-09 17:02:32 +02:00
parent cc9099752f
commit fd8747e4aa
24 changed files with 280 additions and 90 deletions

View file

@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Video conference. - Video conference.
- Log viewer.
- Option to set the display name in "using an account" tab of assistant.
### Fixed ### Fixed
- Crash on exit. - Crash on exit.

View file

@ -2023,6 +2023,10 @@ Klik her: <a href="%1">%1</a>
<extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment> <extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>viewlogs</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsAudio</name> <name>SettingsAudio</name>

View file

@ -2023,6 +2023,10 @@ Klicken Sie hier: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment> <extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment>
<translation>Keine Plugins zu laden</translation> <translation>Keine Plugins zu laden</translation>
</message> </message>
<message>
<source>viewlogs</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsAudio</name> <name>SettingsAudio</name>

View file

@ -2023,6 +2023,10 @@ Click here: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment> <extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment>
<translation>No Plugins to load</translation> <translation>No Plugins to load</translation>
</message> </message>
<message>
<source>viewlogs</source>
<translation>VIEW</translation>
</message>
</context> </context>
<context> <context>
<name>SettingsAudio</name> <name>SettingsAudio</name>

View file

@ -2023,6 +2023,10 @@ Haga clic aquí: &lt;a href=&quot;%1&quot;&gt;%1 &lt;/a&gt;
<extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment> <extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>viewlogs</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsAudio</name> <name>SettingsAudio</name>

View file

@ -2023,6 +2023,10 @@ Cliquez ici : &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment> <extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment>
<translation>Pas de plugin à charger</translation> <translation>Pas de plugin à charger</translation>
</message> </message>
<message>
<source>viewlogs</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsAudio</name> <name>SettingsAudio</name>

View file

@ -2011,6 +2011,10 @@ Kattintson ide: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment> <extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment>
<translation>Nincsenek betölthető beépülő modulok</translation> <translation>Nincsenek betölthető beépülő modulok</translation>
</message> </message>
<message>
<source>viewlogs</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsAudio</name> <name>SettingsAudio</name>

View file

@ -2023,6 +2023,10 @@ Clicca: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment> <extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>viewlogs</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsAudio</name> <name>SettingsAudio</name>

View file

@ -2011,6 +2011,10 @@
<extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment> <extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>viewlogs</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsAudio</name> <name>SettingsAudio</name>

View file

@ -2035,6 +2035,10 @@ Spustelėkite čia: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment> <extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>viewlogs</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsAudio</name> <name>SettingsAudio</name>

View file

@ -2023,6 +2023,10 @@ Clique aqui: &lt;a href=&quot;%1&quot;&gt;%1 &lt;/a&gt;
<extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment> <extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment>
<translation>Nenhum plug-in para carregar</translation> <translation>Nenhum plug-in para carregar</translation>
</message> </message>
<message>
<source>viewlogs</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsAudio</name> <name>SettingsAudio</name>

View file

@ -2035,6 +2035,10 @@
<extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment> <extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment>
<translation>Нет плагинов для загрузки</translation> <translation>Нет плагинов для загрузки</translation>
</message> </message>
<message>
<source>viewlogs</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsAudio</name> <name>SettingsAudio</name>

View file

@ -2023,6 +2023,10 @@ Klicka här: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment> <extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>viewlogs</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsAudio</name> <name>SettingsAudio</name>

View file

@ -2011,6 +2011,10 @@ Buraya tıklayın: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment> <extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment>
<translation>Yüklenecek eklenti yok</translation> <translation>Yüklenecek eklenti yok</translation>
</message> </message>
<message>
<source>viewlogs</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsAudio</name> <name>SettingsAudio</name>

View file

@ -2035,6 +2035,10 @@
<extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment> <extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>viewlogs</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsAudio</name> <name>SettingsAudio</name>

View file

@ -2011,6 +2011,10 @@
<extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment> <extracomment>&apos;No Plugins to load&apos; : Text in combobox</extracomment>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>viewlogs</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SettingsAudio</name> <name>SettingsAudio</name>

View file

@ -209,3 +209,19 @@ void Logger::init (const shared_ptr<linphone::Config> &config) {
mInstance->enable(SettingsModel::getLogsEnabled(config)); mInstance->enable(SettingsModel::getLogsEnabled(config));
} }
QString Logger::getLogText()const{
QDir path = QString::fromStdString(linphone::Core::getLogCollectionPath());
QString prefix = QString::fromStdString(linphone::Core::getLogCollectionPrefix());
auto files = path.entryInfoList(QStringList(prefix+"*.log"), QDir::Files | QDir::NoSymLinks | QDir::Readable, QDir::Time);
QString result;
for(auto fileInfo : files){
QFile file(fileInfo.filePath());
if (file.open(QIODevice::ReadOnly)) {
QByteArray arr = file.readAll();
result += QString::fromLatin1(arr);
file.close();
}
}
return result;
}

View file

@ -43,6 +43,7 @@ public:
} }
void enable (bool status); void enable (bool status);
QString getLogText()const;
static void init (const std::shared_ptr<linphone::Config> &config); static void init (const std::shared_ptr<linphone::Config> &config);

View file

@ -1462,6 +1462,10 @@ void SettingsModel::accessAdvancedSettings() {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
QString SettingsModel::getLogText()const{
return Logger::getInstance()->getLogText();
}
QString SettingsModel::getLogsFolder () const { QString SettingsModel::getLogsFolder () const {
return getLogsFolder(mConfig); return getLogsFolder(mConfig);
} }

View file

@ -543,6 +543,8 @@ public:
void accessAdvancedSettings(); void accessAdvancedSettings();
Q_INVOKABLE QString getLogText()const;
QString getLogsFolder () const; QString getLogsFolder () const;
void setLogsFolder (const QString &folder); void setLogsFolder (const QString &folder);

View file

@ -16,7 +16,9 @@ import 'SettingsAdvanced.js' as Logic
// ============================================================================= // =============================================================================
TabContainer { TabContainer {
id: mainItem
color: "#00000000" color: "#00000000"
signal showLogs()
Column { Column {
id: column id: column
spacing: SettingsWindowStyle.forms.spacing spacing: SettingsWindowStyle.forms.spacing
@ -72,6 +74,14 @@ TabContainer {
anchors.right: parent.right anchors.right: parent.right
spacing: SettingsAdvancedStyle.buttons.spacing spacing: SettingsAdvancedStyle.buttons.spacing
TextButtonB {
text: qsTr('viewlogs')
onClicked: {
mainItem.showLogs()
}
}
TextButtonB { TextButtonB {
text: qsTr('cleanLogs') text: qsTr('cleanLogs')

View file

@ -2,6 +2,7 @@ import QtQuick 2.7
import QtQuick.Controls 2.2 import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.3
import Clipboard 1.0
import Common 1.0 import Common 1.0
import Common.Styles 1.0 import Common.Styles 1.0
import Konami 1.0 import Konami 1.0
@ -45,107 +46,173 @@ ApplicationWindow {
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Navigation bar. // Navigation bar.
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
Item{
RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
spacing: 0 Layout.preferredHeight: TabButtonStyle.text.height
RowLayout {
anchors.fill: parent
spacing: 0
TabBar {
id: tabBar
TabBar { onCurrentIndexChanged: SettingsModel.onSettingsTabChanged(currentIndex)
id: tabBar
onCurrentIndexChanged: SettingsModel.onSettingsTabChanged(currentIndex) TabButton {
iconName: TabButtonStyle.icon.sipAccountsIcon
text: qsTr('sipAccountsTab')
width: implicitWidth
}
TabButton { TabButton {
iconName: TabButtonStyle.icon.sipAccountsIcon iconName: TabButtonStyle.icon.audioIcon
text: qsTr('sipAccountsTab') text: qsTr('audioTab')
width: implicitWidth width: implicitWidth
} }
TabButton { TabButton {
iconName: TabButtonStyle.icon.audioIcon enabled: SettingsModel.videoSupported
text: qsTr('audioTab') iconName: TabButtonStyle.icon.videoIcon
width: implicitWidth text: qsTr('videoTab')
} width: implicitWidth
}
TabButton { TabButton {
enabled: SettingsModel.videoSupported iconName: TabButtonStyle.icon.callIcon
iconName: TabButtonStyle.icon.videoIcon text: qsTr('callsAndChatTab')
text: qsTr('videoTab') width: implicitWidth
width: implicitWidth }
}
TabButton { TabButton {
iconName: TabButtonStyle.icon.callIcon enabled: SettingsModel.showNetworkSettings || SettingsModel.developerSettingsEnabled
text: qsTr('callsAndChatTab') iconName: TabButtonStyle.icon.networkIcon
width: implicitWidth text: qsTr('networkTab')
} width: implicitWidth
}
TabButton { TabButton {
enabled: SettingsModel.showNetworkSettings || SettingsModel.developerSettingsEnabled visible: SettingsModel.tunnelAvailable()
iconName: TabButtonStyle.icon.networkIcon enabled: visible
text: qsTr('networkTab') iconName: TabButtonStyle.icon.sipAccountsIcon
width: implicitWidth //: 'Tunnel' : Tab title for tunnel section in settings.
} text: qsTr('tunnelTab')
width: visible ? implicitWidth : 0
}
TabButton { TabButton {
visible: SettingsModel.tunnelAvailable() iconName: TabButtonStyle.icon.advancedIcon
enabled: visible text: qsTr('uiTab')
iconName: TabButtonStyle.icon.sipAccountsIcon width: implicitWidth
//: 'Tunnel' : Tab title for tunnel section in settings. }
text: qsTr('tunnelTab')
width: visible ? implicitWidth : 0
}
TabButton { TabButton {
iconName: TabButtonStyle.icon.advancedIcon iconName: TabButtonStyle.icon.advancedIcon
text: qsTr('uiTab') text: qsTr('uiAdvanced')
width: implicitWidth width: implicitWidth
}
TabButton {
iconName: TabButtonStyle.icon.advancedIcon
text: qsTr('uiAdvanced')
width: implicitWidth
}
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: TabButtonStyle.text.height
color: TabButtonStyle.backgroundColor.normal
MouseArea {
anchors.fill: parent
onClicked: konami.forceActiveFocus()
cursorShape: Qt.ArrowCursor
Konami {
id: konami
onTriggered: SettingsModel.developerSettingsEnabled = true
} }
} }
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: TabButtonStyle.text.height
color: TabButtonStyle.backgroundColor.normal
MouseArea {
anchors.fill: parent
onClicked: konami.forceActiveFocus()
cursorShape: Qt.ArrowCursor
Konami {
id: konami
onTriggered: SettingsModel.developerSettingsEnabled = true
}
}
}
}
Rectangle{
id: hideBar
anchors.fill: parent
color: TabButtonStyle.backgroundColor.normal
visible: logViewer.active
} }
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Content. // Content.
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
Item{
StackLayout {
Layout.fillHeight: true Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
StackLayout {
anchors.fill: parent
currentIndex: tabBar.currentIndex currentIndex: tabBar.currentIndex
SettingsSipAccounts {} SettingsSipAccounts {}
SettingsAudio {} SettingsAudio {}
SettingsVideo {} SettingsVideo {}
SettingsCallsChat {} SettingsCallsChat {}
SettingsNetwork {} SettingsNetwork {}
SettingsTunnel {} SettingsTunnel {}
SettingsUi {} SettingsUi {}
SettingsAdvanced {} SettingsAdvanced {onShowLogs: logViewer.active=true }
}
Loader{
id: logViewer
anchors.fill: parent
active: false
sourceComponent: Component{
Rectangle{
id: logBackground
anchors.fill: parent
property variant stringList: null
function updateText() {
stringList = SettingsModel.getLogText().split('\n')
idContentListView.positionViewAtEnd()
}
Component.onCompleted: updateText()
ColumnLayout{
anchors.fill: parent
RowLayout{// Prepare for other actions
ActionButton{
Layout.topMargin: 5
Layout.leftMargin: 5
backgroundRadius: width/2
isCustom: true
colorSet: SettingsWindowStyle.buttons.back
onClicked: logViewer.active = false
}
ActionButton{
Layout.topMargin: 5
Layout.leftMargin: 5
backgroundRadius: width/2
isCustom: true
colorSet: SettingsWindowStyle.buttons.copy
onClicked: {updating = true ; Clipboard.text = SettingsModel.getLogText();updating=false}
}
}
ListView {
id: idContentListView
model: logBackground.stringList
Layout.fillHeight: true
Layout.fillWidth: true
Layout.topMargin: 20
Layout.leftMargin: 10
Layout.rightMargin: 10
delegate: Text {
width: idContentListView.width
text: model.modelData
font.pointSize: FormTableStyle.entry.text.pointSize
textFormat: Text.PlainText
wrapMode: Text.Wrap
}
ScrollBar.vertical: ScrollBar {}
}
}
}
}
}
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------

View file

@ -54,5 +54,33 @@ QtObject {
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'me_h_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 color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'me_p_b_fg').color
} }
property QtObject back: QtObject {
property int iconSize: 35
property string icon : 'back_custom'
property string name : 'back'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 's_n_b_bg').color
property color backgroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_d', icon, 's_d_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 foregroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_d', icon, 's_d_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 copy: QtObject {
property int iconSize: 30
property string icon : 'copy_custom'
property string name : 'copy'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'l_n_b_bg').color
property color backgroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_d', icon, 'l_d_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 backgroundUpdatingColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_u', icon, 'l_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'l_n_b_fg').color
property color foregroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_d', icon, 'l_d_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 color foregroundUpdatingColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_u', icon, 'l_p_b_fg').color
}
} }
} }

@ -1 +1 @@
Subproject commit 9542d335ea525de66d7b5519bac4e1ba808caa3a Subproject commit 1355eaf8e34f3505f3812743bd2232e01558fde2