fix #LINQT-1573 delete all history for one address
+ spinner call history
This commit is contained in:
parent
19db70ca75
commit
38a718ca0a
10 changed files with 387 additions and 307 deletions
|
|
@ -22,6 +22,7 @@
|
||||||
#include "CallHistoryGui.hpp"
|
#include "CallHistoryGui.hpp"
|
||||||
#include "core/App.hpp"
|
#include "core/App.hpp"
|
||||||
#include "model/object/VariantObject.hpp"
|
#include "model/object/VariantObject.hpp"
|
||||||
|
#include "model/tool/ToolModel.hpp"
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <linphone++/linphone.hh>
|
#include <linphone++/linphone.hh>
|
||||||
|
|
||||||
|
|
@ -97,6 +98,28 @@ void CallHistoryList::setSelf(QSharedPointer<CallHistoryList> me) {
|
||||||
delete[] callLogs;
|
delete[] callLogs;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
mModelConnection->makeConnectToCore(&CallHistoryList::lRemoveEntriesForAddress, [this](QString address) {
|
||||||
|
mModelConnection->invokeToModel([this, address]() {
|
||||||
|
if (auto account = CoreModel::getInstance()->getCore()->getDefaultAccount()) {
|
||||||
|
auto linAddress = ToolModel::interpretUrl(address);
|
||||||
|
if (linAddress) {
|
||||||
|
auto core = CoreModel::getInstance()->getCore();
|
||||||
|
auto accountAddress = account->getParams() ? account->getParams()->getIdentityAddress() : nullptr;
|
||||||
|
if (accountAddress)
|
||||||
|
for (auto &callLog : core->getCallHistory(linAddress, accountAddress)) {
|
||||||
|
core->removeCallLog(callLog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
mModelConnection->makeConnectToCore(&CallHistoryList::lRemoveAllEntries, [this]() {
|
||||||
|
mModelConnection->invokeToModel([this]() {
|
||||||
|
if (auto account = CoreModel::getInstance()->getCore()->getDefaultAccount()) {
|
||||||
|
account->clearCallLogs();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
emit lUpdate();
|
emit lUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,6 +135,17 @@ void CallHistoryList::removeAllEntries() {
|
||||||
}
|
}
|
||||||
mList.clear();
|
mList.clear();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
|
emit lRemoveAllEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallHistoryList::removeEntriesWithFilter(QString filter) {
|
||||||
|
for (auto it = mList.rbegin(); it != mList.rend(); ++it) {
|
||||||
|
auto callHistory = it->objectCast<CallHistoryCore>();
|
||||||
|
if (callHistory->mDisplayName.contains(filter) || callHistory->mRemoteAddress.contains(filter)) {
|
||||||
|
callHistory->remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit lRemoveEntriesForAddress(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallHistoryList::remove(const int &row) {
|
void CallHistoryList::remove(const int &row) {
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ public:
|
||||||
void toConnect(CallHistoryCore *data);
|
void toConnect(CallHistoryCore *data);
|
||||||
|
|
||||||
void removeAllEntries();
|
void removeAllEntries();
|
||||||
|
void removeEntriesWithFilter(QString filter);
|
||||||
void remove(const int &row);
|
void remove(const int &row);
|
||||||
|
|
||||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
@ -59,6 +60,8 @@ public:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void lUpdate();
|
void lUpdate();
|
||||||
|
void lRemoveEntriesForAddress(QString address);
|
||||||
|
void lRemoveAllEntries();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Check the state from CallHistoryCore: sender() must be a CallHistoryCore.
|
// Check the state from CallHistoryCore: sender() must be a CallHistoryCore.
|
||||||
|
|
|
||||||
|
|
@ -38,15 +38,8 @@ void CallHistoryProxy::removeAllEntries() {
|
||||||
mHistoryList->removeAllEntries();
|
mHistoryList->removeAllEntries();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallHistoryProxy::removeEntriesWithFilter() {
|
void CallHistoryProxy::removeEntriesWithFilter(QString filter) {
|
||||||
QList<QSharedPointer<CallHistoryCore>> itemList(rowCount());
|
mHistoryList->removeEntriesWithFilter(filter);
|
||||||
for (auto i = rowCount() - 1; i >= 0; --i) {
|
|
||||||
auto item = getItemAt<SortFilterList, CallHistoryList, CallHistoryCore>(i);
|
|
||||||
itemList[i] = item;
|
|
||||||
}
|
|
||||||
for (auto item : itemList) {
|
|
||||||
item->remove();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallHistoryProxy::reload() {
|
void CallHistoryProxy::reload() {
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ public:
|
||||||
~CallHistoryProxy();
|
~CallHistoryProxy();
|
||||||
|
|
||||||
Q_INVOKABLE void removeAllEntries();
|
Q_INVOKABLE void removeAllEntries();
|
||||||
Q_INVOKABLE void removeEntriesWithFilter();
|
Q_INVOKABLE void removeEntriesWithFilter(QString filter);
|
||||||
Q_INVOKABLE void reload();
|
Q_INVOKABLE void reload();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
||||||
view/Control/Display/Text.qml
|
view/Control/Display/Text.qml
|
||||||
view/Control/Display/ToolTip.qml
|
view/Control/Display/ToolTip.qml
|
||||||
view/Control/Display/Call/CallListView.qml
|
view/Control/Display/Call/CallListView.qml
|
||||||
|
view/Control/Display/Call/CallHistoryListView.qml
|
||||||
view/Control/Display/Call/CallStatistics.qml
|
view/Control/Display/Call/CallStatistics.qml
|
||||||
view/Control/Display/Contact/Avatar.qml
|
view/Control/Display/Contact/Avatar.qml
|
||||||
view/Control/Display/Contact/Contact.qml
|
view/Control/Display/Contact/Contact.qml
|
||||||
|
|
|
||||||
227
Linphone/view/Control/Display/Call/CallHistoryListView.qml
Normal file
227
Linphone/view/Control/Display/Call/CallHistoryListView.qml
Normal file
|
|
@ -0,0 +1,227 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Controls.Basic as Control
|
||||||
|
import Linphone
|
||||||
|
import UtilsCpp
|
||||||
|
import SettingsCpp
|
||||||
|
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle
|
||||||
|
import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: mainItem
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
property SearchBar searchBar
|
||||||
|
property bool loading: false
|
||||||
|
property string searchText: searchBar?.text
|
||||||
|
|
||||||
|
signal resultsReceived()
|
||||||
|
|
||||||
|
onResultsReceived: {
|
||||||
|
loading = false
|
||||||
|
// contentY = 0
|
||||||
|
}
|
||||||
|
onSearchTextChanged: loading = true
|
||||||
|
|
||||||
|
model: CallHistoryProxy {
|
||||||
|
id: callHistoryProxy
|
||||||
|
filterText: mainItem.searchText
|
||||||
|
onFilterTextChanged: maxDisplayItems = initialDisplayItems
|
||||||
|
initialDisplayItems: Math.max(20, 2 * mainItem.height / (56 * DefaultStyle.dp))
|
||||||
|
displayItemsStep: 3 * initialDisplayItems / 2
|
||||||
|
onModelReset: {
|
||||||
|
mainItem.resultsReceived()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flickDeceleration: 10000
|
||||||
|
spacing: 10 * DefaultStyle.dp
|
||||||
|
|
||||||
|
Keys.onPressed: (event) => {
|
||||||
|
if(event.key == Qt.Key_Escape){
|
||||||
|
console.log("Back")
|
||||||
|
searchBar.forceActiveFocus()
|
||||||
|
event.accepted = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: cacheBuffer = Math.max(contentHeight,0)//contentHeight>0 ? contentHeight : 0// cache all items
|
||||||
|
// remove binding loop
|
||||||
|
onContentHeightChanged: Qt.callLater(function(){
|
||||||
|
if (mainItem) mainItem.cacheBuffer = Math?.max(contentHeight,0) || 0
|
||||||
|
})
|
||||||
|
|
||||||
|
onActiveFocusChanged: if(activeFocus && currentIndex < 0 && count > 0) currentIndex = 0
|
||||||
|
onCountChanged: {
|
||||||
|
if(currentIndex < 0 && count > 0){
|
||||||
|
mainItem.currentIndex = 0 // Select first item after loading model
|
||||||
|
}
|
||||||
|
if(atYBeginning)
|
||||||
|
positionViewAtBeginning()// Stay at beginning
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: deleteHistoryPopup
|
||||||
|
function onAccepted() {
|
||||||
|
mainItem.model.removeAllEntries()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onAtYEndChanged: {
|
||||||
|
if(atYEnd && count > 0){
|
||||||
|
callHistoryProxy.displayMore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
function moveToCurrentItem(){
|
||||||
|
if( mainItem.currentIndex >= 0)
|
||||||
|
Utils.updatePosition(mainItem, mainItem)
|
||||||
|
}
|
||||||
|
onCurrentItemChanged: {
|
||||||
|
moveToCurrentItem()
|
||||||
|
}
|
||||||
|
// Update position only if we are moving to current item and its position is changing.
|
||||||
|
property var _currentItemY: currentItem?.y
|
||||||
|
on_CurrentItemYChanged: if(_currentItemY && moveAnimation.running){
|
||||||
|
moveToCurrentItem()
|
||||||
|
}
|
||||||
|
Behavior on contentY{
|
||||||
|
NumberAnimation {
|
||||||
|
id: moveAnimation
|
||||||
|
duration: 500
|
||||||
|
easing.type: Easing.OutExpo
|
||||||
|
alwaysRunToEnd: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
onVisibleChanged: {
|
||||||
|
if (!visible) currentIndex = -1
|
||||||
|
}
|
||||||
|
// Qt bug: sometimes, containsMouse may not be send and update on each MouseArea.
|
||||||
|
// So we need to use this variable to switch off all hovered items.
|
||||||
|
property int lastMouseContainsIndex: -1
|
||||||
|
delegate: FocusScope {
|
||||||
|
width:mainItem.width
|
||||||
|
height: 56 * DefaultStyle.dp
|
||||||
|
visible: !!modelData
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
z: 1
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 10 * DefaultStyle.dp
|
||||||
|
spacing: 10 * DefaultStyle.dp
|
||||||
|
Avatar {
|
||||||
|
id: historyAvatar
|
||||||
|
property var contactObj: UtilsCpp.findFriendByAddress(modelData.core.remoteAddress)
|
||||||
|
contact: contactObj?.value || null
|
||||||
|
_address: modelData.core.conferenceInfo
|
||||||
|
? modelData.core.conferenceInfo.core.subject
|
||||||
|
: modelData.core.remoteAddress
|
||||||
|
secured: securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
||||||
|
width: 45 * DefaultStyle.dp
|
||||||
|
height: 45 * DefaultStyle.dp
|
||||||
|
isConference: modelData.core.isConference
|
||||||
|
}
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 5 * DefaultStyle.dp
|
||||||
|
Text {
|
||||||
|
id: friendAddress
|
||||||
|
Layout.fillWidth: true
|
||||||
|
maximumLineCount: 1
|
||||||
|
text: historyAvatar.displayNameVal
|
||||||
|
font {
|
||||||
|
pixelSize: 14 * DefaultStyle.dp
|
||||||
|
weight: 400 * DefaultStyle.dp
|
||||||
|
capitalization: Font.Capitalize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
spacing: 6 * DefaultStyle.dp
|
||||||
|
EffectImage {
|
||||||
|
id: statusIcon
|
||||||
|
imageSource: modelData.core.status === LinphoneEnums.CallStatus.Declined
|
||||||
|
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|
||||||
|
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|
||||||
|
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted
|
||||||
|
? AppIcons.arrowElbow
|
||||||
|
: modelData.core.isOutgoing
|
||||||
|
? AppIcons.arrowUpRight
|
||||||
|
: AppIcons.arrowDownLeft
|
||||||
|
colorizationColor: modelData.core.status === LinphoneEnums.CallStatus.Declined
|
||||||
|
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|
||||||
|
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|
||||||
|
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted
|
||||||
|
|| modelData.core.status === LinphoneEnums.CallStatus.Missed
|
||||||
|
? DefaultStyle.danger_500main
|
||||||
|
: modelData.core.isOutgoing
|
||||||
|
? DefaultStyle.info_500_main
|
||||||
|
: DefaultStyle.success_500main
|
||||||
|
Layout.preferredWidth: 12 * DefaultStyle.dp
|
||||||
|
Layout.preferredHeight: 12 * DefaultStyle.dp
|
||||||
|
transform: Rotation {
|
||||||
|
angle: modelData.core.isOutgoing && (modelData.core.status === LinphoneEnums.CallStatus.Declined
|
||||||
|
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|
||||||
|
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|
||||||
|
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted) ? 180 : 0
|
||||||
|
origin {
|
||||||
|
x: statusIcon.width/2
|
||||||
|
y: statusIcon.height/2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
// text: modelData.core.date
|
||||||
|
text: UtilsCpp.formatDate(modelData.core.date)
|
||||||
|
font {
|
||||||
|
pixelSize: 12 * DefaultStyle.dp
|
||||||
|
weight: 300 * DefaultStyle.dp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BigButton {
|
||||||
|
style: ButtonStyle.noBackground
|
||||||
|
icon.source: AppIcons.phone
|
||||||
|
focus: true
|
||||||
|
activeFocusOnTab: false
|
||||||
|
onClicked: {
|
||||||
|
if (modelData.core.isConference) {
|
||||||
|
var callsWindow = UtilsCpp.getCallsWindow()
|
||||||
|
callsWindow.setupConference(modelData.core.conferenceInfo)
|
||||||
|
UtilsCpp.smartShowWindow(callsWindow)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
UtilsCpp.createCall(modelData.core.remoteAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
hoverEnabled: true
|
||||||
|
anchors.fill: parent
|
||||||
|
focus: true
|
||||||
|
onContainsMouseChanged: {
|
||||||
|
if(containsMouse)
|
||||||
|
mainItem.lastMouseContainsIndex = index
|
||||||
|
else if( mainItem.lastMouseContainsIndex == index)
|
||||||
|
mainItem.lastMouseContainsIndex = -1
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
opacity: 0.7
|
||||||
|
radius: 8 * DefaultStyle.dp
|
||||||
|
color: mainItem.currentIndex === index ? DefaultStyle.main2_200 : DefaultStyle.main2_100
|
||||||
|
visible: mainItem.lastMouseContainsIndex === index || mainItem.currentIndex === index
|
||||||
|
}
|
||||||
|
onPressed: {
|
||||||
|
mainItem.currentIndex = model.index
|
||||||
|
mainItem.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Control.ScrollBar.vertical: scrollbar
|
||||||
|
}
|
||||||
|
|
@ -32,7 +32,7 @@ LoginLayout {
|
||||||
}
|
}
|
||||||
EffectImage {
|
EffectImage {
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
source: AppIcons.profile
|
imageSource: AppIcons.profile
|
||||||
Layout.preferredHeight: 34 * DefaultStyle.dp
|
Layout.preferredHeight: 34 * DefaultStyle.dp
|
||||||
Layout.preferredWidth: 34 * DefaultStyle.dp
|
Layout.preferredWidth: 34 * DefaultStyle.dp
|
||||||
colorizationColor: DefaultStyle.main2_600
|
colorizationColor: DefaultStyle.main2_600
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,7 @@ AbstractSettingsLayout {
|
||||||
Component {
|
Component {
|
||||||
id: videoCodecsComponent
|
id: videoCodecsComponent
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
spacing: 20 * DefaultStyle.dp
|
||||||
ListView {
|
ListView {
|
||||||
Layout.preferredHeight: contentHeight
|
Layout.preferredHeight: contentHeight
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
|
||||||
|
|
@ -214,213 +214,32 @@ AbstractMainPage {
|
||||||
weight: 800 * DefaultStyle.dp
|
weight: 800 * DefaultStyle.dp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ListView {
|
BusyIndicator {
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
Layout.preferredHeight: visible ? 60 * DefaultStyle.dp : 0
|
||||||
|
Layout.preferredWidth: 60 * DefaultStyle.dp
|
||||||
|
indicatorHeight: 60 * DefaultStyle.dp
|
||||||
|
indicatorWidth: 60 * DefaultStyle.dp
|
||||||
|
visible: historyListView.loading
|
||||||
|
indicatorColor: DefaultStyle.main1_500_main
|
||||||
|
}
|
||||||
|
CallHistoryListView {
|
||||||
id: historyListView
|
id: historyListView
|
||||||
clip: true
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
model: CallHistoryProxy {
|
searchBar: searchBar
|
||||||
id: callHistoryProxy
|
|
||||||
filterText: searchBar.text
|
|
||||||
onFilterTextChanged: maxDisplayItems = initialDisplayItems
|
|
||||||
initialDisplayItems: Math.max(20, 2 * historyListView.height / (56 * DefaultStyle.dp))
|
|
||||||
displayItemsStep: 3 * initialDisplayItems / 2
|
|
||||||
}
|
|
||||||
cacheBuffer: contentHeight>0 ? contentHeight : 0// cache all items
|
|
||||||
flickDeceleration: 10000
|
|
||||||
spacing: 10 * DefaultStyle.dp
|
|
||||||
|
|
||||||
Keys.onPressed: (event) => {
|
|
||||||
if(event.key == Qt.Key_Escape){
|
|
||||||
console.log("Back")
|
|
||||||
searchBar.forceActiveFocus()
|
|
||||||
event.accepted = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// remove binding loop
|
|
||||||
onContentHeightChanged: Qt.callLater(function(){
|
|
||||||
historyListView.cacheBuffer = Math.max(contentHeight,0)
|
|
||||||
})
|
|
||||||
onActiveFocusChanged: if(activeFocus && currentIndex < 0 && count > 0) currentIndex = 0
|
|
||||||
onCountChanged: {
|
|
||||||
if(currentIndex < 0 && count > 0){
|
|
||||||
historyListView.currentIndex = 0 // Select first item after loading model
|
|
||||||
}
|
|
||||||
if(atYBeginning)
|
|
||||||
positionViewAtBeginning()// Stay at beginning
|
|
||||||
}
|
|
||||||
Connections {
|
|
||||||
target: deleteHistoryPopup
|
|
||||||
function onAccepted() {
|
|
||||||
historyListView.model.removeAllEntries()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Connections{
|
Connections{
|
||||||
target: mainItem
|
target: mainItem
|
||||||
function onListViewUpdated(){
|
function onListViewUpdated(){
|
||||||
callHistoryProxy.reload()
|
historyListView.model.reload()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onAtYEndChanged: {
|
|
||||||
if(atYEnd && count > 0){
|
|
||||||
callHistoryProxy.displayMore()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
function moveToCurrentItem(){
|
|
||||||
if( historyListView.currentIndex >= 0)
|
|
||||||
Utils.updatePosition(historyListView, historyListView)
|
|
||||||
}
|
|
||||||
onCurrentItemChanged: {
|
|
||||||
moveToCurrentItem()
|
|
||||||
}
|
|
||||||
// Update position only if we are moving to current item and its position is changing.
|
|
||||||
property var _currentItemY: currentItem?.y
|
|
||||||
on_CurrentItemYChanged: if(_currentItemY && moveAnimation.running){
|
|
||||||
moveToCurrentItem()
|
|
||||||
}
|
|
||||||
Behavior on contentY{
|
|
||||||
NumberAnimation {
|
|
||||||
id: moveAnimation
|
|
||||||
duration: 500
|
|
||||||
easing.type: Easing.OutExpo
|
|
||||||
alwaysRunToEnd: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
|
|
||||||
onCurrentIndexChanged: {
|
onCurrentIndexChanged: {
|
||||||
mainItem.selectedRowHistoryGui = model.getAt(currentIndex)
|
mainItem.selectedRowHistoryGui = model.getAt(currentIndex)
|
||||||
}
|
}
|
||||||
onVisibleChanged: {
|
onCountChanged: {
|
||||||
if (!visible) currentIndex = -1
|
mainItem.selectedRowHistoryGui = model.getAt(currentIndex)
|
||||||
}
|
}
|
||||||
// Qt bug: sometimes, containsMouse may not be send and update on each MouseArea.
|
|
||||||
// So we need to use this variable to switch off all hovered items.
|
|
||||||
property int lastMouseContainsIndex: -1
|
|
||||||
delegate: FocusScope {
|
|
||||||
width:historyListView.width
|
|
||||||
height: 56 * DefaultStyle.dp
|
|
||||||
visible: !!modelData
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
z: 1
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: 10 * DefaultStyle.dp
|
|
||||||
spacing: 10 * DefaultStyle.dp
|
|
||||||
Avatar {
|
|
||||||
id: historyAvatar
|
|
||||||
property var contactObj: UtilsCpp.findFriendByAddress(modelData.core.remoteAddress)
|
|
||||||
contact: contactObj?.value || null
|
|
||||||
_address: modelData.core.conferenceInfo
|
|
||||||
? modelData.core.conferenceInfo.core.subject
|
|
||||||
: modelData.core.remoteAddress
|
|
||||||
secured: securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
|
||||||
width: 45 * DefaultStyle.dp
|
|
||||||
height: 45 * DefaultStyle.dp
|
|
||||||
isConference: modelData.core.isConference
|
|
||||||
}
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: true
|
|
||||||
spacing: 5 * DefaultStyle.dp
|
|
||||||
Text {
|
|
||||||
id: friendAddress
|
|
||||||
Layout.fillWidth: true
|
|
||||||
maximumLineCount: 1
|
|
||||||
text: historyAvatar.displayNameVal
|
|
||||||
font {
|
|
||||||
pixelSize: 14 * DefaultStyle.dp
|
|
||||||
weight: 400 * DefaultStyle.dp
|
|
||||||
capitalization: Font.Capitalize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RowLayout {
|
|
||||||
spacing: 6 * DefaultStyle.dp
|
|
||||||
EffectImage {
|
|
||||||
id: statusIcon
|
|
||||||
imageSource: modelData.core.status === LinphoneEnums.CallStatus.Declined
|
|
||||||
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|
|
||||||
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|
|
||||||
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted
|
|
||||||
? AppIcons.arrowElbow
|
|
||||||
: modelData.core.isOutgoing
|
|
||||||
? AppIcons.arrowUpRight
|
|
||||||
: AppIcons.arrowDownLeft
|
|
||||||
colorizationColor: modelData.core.status === LinphoneEnums.CallStatus.Declined
|
|
||||||
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|
|
||||||
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|
|
||||||
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted
|
|
||||||
|| modelData.core.status === LinphoneEnums.CallStatus.Missed
|
|
||||||
? DefaultStyle.danger_500main
|
|
||||||
: modelData.core.isOutgoing
|
|
||||||
? DefaultStyle.info_500_main
|
|
||||||
: DefaultStyle.success_500main
|
|
||||||
Layout.preferredWidth: 12 * DefaultStyle.dp
|
|
||||||
Layout.preferredHeight: 12 * DefaultStyle.dp
|
|
||||||
transform: Rotation {
|
|
||||||
angle: modelData.core.isOutgoing && (modelData.core.status === LinphoneEnums.CallStatus.Declined
|
|
||||||
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|
|
||||||
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|
|
||||||
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted) ? 180 : 0
|
|
||||||
origin {
|
|
||||||
x: statusIcon.width/2
|
|
||||||
y: statusIcon.height/2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
// text: modelData.core.date
|
|
||||||
text: UtilsCpp.formatDate(modelData.core.date)
|
|
||||||
font {
|
|
||||||
pixelSize: 12 * DefaultStyle.dp
|
|
||||||
weight: 300 * DefaultStyle.dp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BigButton {
|
|
||||||
style: ButtonStyle.noBackground
|
|
||||||
icon.source: AppIcons.phone
|
|
||||||
focus: true
|
|
||||||
activeFocusOnTab: false
|
|
||||||
onClicked: {
|
|
||||||
if (modelData.core.isConference) {
|
|
||||||
var callsWindow = UtilsCpp.getCallsWindow()
|
|
||||||
callsWindow.setupConference(modelData.core.conferenceInfo)
|
|
||||||
UtilsCpp.smartShowWindow(callsWindow)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
UtilsCpp.createCall(modelData.core.remoteAddress)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MouseArea {
|
|
||||||
hoverEnabled: true
|
|
||||||
anchors.fill: parent
|
|
||||||
focus: true
|
|
||||||
onContainsMouseChanged: {
|
|
||||||
if(containsMouse)
|
|
||||||
historyListView.lastMouseContainsIndex = index
|
|
||||||
else if( historyListView.lastMouseContainsIndex == index)
|
|
||||||
historyListView.lastMouseContainsIndex = -1
|
|
||||||
}
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
opacity: 0.7
|
|
||||||
radius: 8 * DefaultStyle.dp
|
|
||||||
color: historyListView.currentIndex === index ? DefaultStyle.main2_200 : DefaultStyle.main2_100
|
|
||||||
visible: historyListView.lastMouseContainsIndex === index || historyListView.currentIndex === index
|
|
||||||
}
|
|
||||||
onPressed: {
|
|
||||||
historyListView.currentIndex = model.index
|
|
||||||
historyListView.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Control.ScrollBar.vertical: scrollbar
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -711,7 +530,7 @@ AbstractMainPage {
|
||||||
Connections {
|
Connections {
|
||||||
target: deleteForUserPopup
|
target: deleteForUserPopup
|
||||||
function onAccepted() {
|
function onAccepted() {
|
||||||
detailListView.model.removeEntriesWithFilter()
|
detailListView.model.removeEntriesWithFilter(detailListView.searchText)
|
||||||
mainItem.listViewUpdated()
|
mainItem.listViewUpdated()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -726,32 +545,33 @@ AbstractMainPage {
|
||||||
detailContent: RoundedPane {
|
detailContent: RoundedPane {
|
||||||
id: detailControl
|
id: detailControl
|
||||||
Layout.preferredWidth: 360 * DefaultStyle.dp
|
Layout.preferredWidth: 360 * DefaultStyle.dp
|
||||||
implicitHeight: 430 * DefaultStyle.dp + topPadding + bottomPadding
|
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
id: detailListBackground
|
id: detailListBackground
|
||||||
width: parent.width
|
anchors.fill: parent
|
||||||
height: detailListView.height
|
|
||||||
color: DefaultStyle.grey_0
|
color: DefaultStyle.grey_0
|
||||||
radius: 15 * DefaultStyle.dp
|
radius: 15 * DefaultStyle.dp
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
contentItem: StackLayout {
|
||||||
id: detailListView
|
currentIndex: detailListView.loading ? 0 : 1
|
||||||
width: parent.width
|
height: Math.min(430 * DefaultStyle.dp, detailListView.contentHeight)
|
||||||
height: Math.min(detailControl.implicitHeight, contentHeight)
|
BusyIndicator {
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
spacing: 20 * DefaultStyle.dp
|
Layout.preferredHeight: visible ? 60 * DefaultStyle.dp : 0
|
||||||
clip: true
|
Layout.preferredWidth: 60 * DefaultStyle.dp
|
||||||
|
indicatorHeight: 60 * DefaultStyle.dp
|
||||||
model: CallHistoryProxy {
|
indicatorWidth: 60 * DefaultStyle.dp
|
||||||
id: detailsHistoryProxy
|
indicatorColor: DefaultStyle.main1_500_main
|
||||||
filterText: mainItem.selectedRowHistoryGui ? mainItem.selectedRowHistoryGui.core.remoteAddress : ""
|
|
||||||
onFilterTextChanged: maxDisplayItems = initialDisplayItems
|
|
||||||
initialDisplayItems: Math.max(20, 2 * detailListView.height / (56 * DefaultStyle.dp))
|
|
||||||
displayItemsStep: 3 * initialDisplayItems / 2
|
|
||||||
}
|
}
|
||||||
onAtYEndChanged: if(atYEnd) detailsHistoryProxy.displayMore()
|
CallHistoryListView {
|
||||||
|
id: detailListView
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: Math.min(detailControl.implicitHeight, contentHeight)
|
||||||
|
spacing: 14 * DefaultStyle.dp
|
||||||
|
clip: true
|
||||||
|
searchText: mainItem.selectedRowHistoryGui ? mainItem.selectedRowHistoryGui.core.remoteAddress : ""
|
||||||
|
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
width:detailListView.width
|
width:detailListView.width
|
||||||
height: 56 * DefaultStyle.dp
|
height: 56 * DefaultStyle.dp
|
||||||
|
|
@ -831,6 +651,7 @@ AbstractMainPage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Item{
|
Item{
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue