Add a new progress bar in the form of spinner.

Allow to cancel a file transfer.
Open folder if the file cannot be directly open (don't work if the system accept but reject it).
This commit is contained in:
Julien Wadel 2022-06-17 16:08:27 +02:00
parent 721196a2a2
commit 571ef7b79c
27 changed files with 359 additions and 69 deletions

View file

@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Option to set the display name in "using an account" tab of assistant.
- Long pressed buttons.
- Phone dialpad on main window.
- Animated file in chats/notifications.
- Round progress bar for transferring a file and allow to cancel it.
### Fixed
- Crash on exit.

View file

@ -550,6 +550,19 @@ Server url ikke konfigureret.</translation>
<extra-Context>%1 is someone. The state is that the message hasn&apos;t been delivered because of an error.</extra-Context>
</message>
</context>
<context>
<name>ChatFileMessage</name>
<message>
<source>fileTransferCancel</source>
<extracomment>&apos;Cancel&apos; : Message link to cancel a transfer (upload/download)</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>fileTransferDownload</source>
<extracomment>&apos;Download&apos; : Message link to download a file</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatForwardMessage</name>
<message>

View file

@ -550,6 +550,19 @@ Server URL ist nicht konfiguriert.</translation>
<extra-Context>%1 is someone. The state is that the message hasn&apos;t been delivered because of an error.</extra-Context>
</message>
</context>
<context>
<name>ChatFileMessage</name>
<message>
<source>fileTransferCancel</source>
<extracomment>&apos;Cancel&apos; : Message link to cancel a transfer (upload/download)</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>fileTransferDownload</source>
<extracomment>&apos;Download&apos; : Message link to download a file</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatForwardMessage</name>
<message>

View file

@ -550,6 +550,19 @@ Server URL not configured.</translation>
<extra-Context>%1 is someone. The state is that the message hasn&apos;t been delivered because of an error.</extra-Context>
</message>
</context>
<context>
<name>ChatFileMessage</name>
<message>
<source>fileTransferCancel</source>
<extracomment>&apos;Cancel&apos; : Message link to cancel a transfer (upload/download)</extracomment>
<translation>Cancel</translation>
</message>
<message>
<source>fileTransferDownload</source>
<extracomment>&apos;Download&apos; : Message link to download a file</extracomment>
<translation>Download</translation>
</message>
</context>
<context>
<name>ChatForwardMessage</name>
<message>

View file

@ -550,6 +550,19 @@ URL del servidor no configurada.</translation>
<extra-Context>%1 is someone. The state is that the message hasn&apos;t been delivered because of an error.</extra-Context>
</message>
</context>
<context>
<name>ChatFileMessage</name>
<message>
<source>fileTransferCancel</source>
<extracomment>&apos;Cancel&apos; : Message link to cancel a transfer (upload/download)</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>fileTransferDownload</source>
<extracomment>&apos;Download&apos; : Message link to download a file</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatForwardMessage</name>
<message>

View file

@ -550,6 +550,19 @@ URL du serveur non configurée.</translation>
<extra-Context>%1 is someone. The state is that the message hasn&apos;t been delivered because of an error.</extra-Context>
</message>
</context>
<context>
<name>ChatFileMessage</name>
<message>
<source>fileTransferCancel</source>
<extracomment>&apos;Cancel&apos; : Message link to cancel a transfer (upload/download)</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>fileTransferDownload</source>
<extracomment>&apos;Download&apos; : Message link to download a file</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatForwardMessage</name>
<message>

View file

@ -549,6 +549,19 @@ A kiszolgáló URL-je nincs konfigurálva.</translation>
<extra-Context>%1 is someone. The state is that the message hasn&apos;t been delivered because of an error.</extra-Context>
</message>
</context>
<context>
<name>ChatFileMessage</name>
<message>
<source>fileTransferCancel</source>
<extracomment>&apos;Cancel&apos; : Message link to cancel a transfer (upload/download)</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>fileTransferDownload</source>
<extracomment>&apos;Download&apos; : Message link to download a file</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatForwardMessage</name>
<message>

View file

@ -550,6 +550,19 @@ URL del server non configurato.</translation>
<extra-Context>%1 is someone. The state is that the message hasn&apos;t been delivered because of an error.</extra-Context>
</message>
</context>
<context>
<name>ChatFileMessage</name>
<message>
<source>fileTransferCancel</source>
<extracomment>&apos;Cancel&apos; : Message link to cancel a transfer (upload/download)</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>fileTransferDownload</source>
<extracomment>&apos;Download&apos; : Message link to download a file</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatForwardMessage</name>
<message>

View file

@ -549,6 +549,19 @@
<extra-Context>%1 is someone. The state is that the message hasn&apos;t been delivered because of an error.</extra-Context>
</message>
</context>
<context>
<name>ChatFileMessage</name>
<message>
<source>fileTransferCancel</source>
<extracomment>&apos;Cancel&apos; : Message link to cancel a transfer (upload/download)</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>fileTransferDownload</source>
<extracomment>&apos;Download&apos; : Message link to download a file</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatForwardMessage</name>
<message>

View file

@ -551,6 +551,19 @@ Nesukonfigūruotas serverio url.</translation>
<extra-Context>%1 is someone. The state is that the message hasn&apos;t been delivered because of an error.</extra-Context>
</message>
</context>
<context>
<name>ChatFileMessage</name>
<message>
<source>fileTransferCancel</source>
<extracomment>&apos;Cancel&apos; : Message link to cancel a transfer (upload/download)</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>fileTransferDownload</source>
<extracomment>&apos;Download&apos; : Message link to download a file</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatForwardMessage</name>
<message>

View file

@ -550,6 +550,19 @@ URL do servidor não configurado.</translation>
<extra-Context>%1 is someone. The state is that the message hasn&apos;t been delivered because of an error.</extra-Context>
</message>
</context>
<context>
<name>ChatFileMessage</name>
<message>
<source>fileTransferCancel</source>
<extracomment>&apos;Cancel&apos; : Message link to cancel a transfer (upload/download)</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>fileTransferDownload</source>
<extracomment>&apos;Download&apos; : Message link to download a file</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatForwardMessage</name>
<message>

View file

@ -551,6 +551,19 @@
<extra-Context>%1 is someone. The state is that the message hasn&apos;t been delivered because of an error.</extra-Context>
</message>
</context>
<context>
<name>ChatFileMessage</name>
<message>
<source>fileTransferCancel</source>
<extracomment>&apos;Cancel&apos; : Message link to cancel a transfer (upload/download)</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>fileTransferDownload</source>
<extracomment>&apos;Download&apos; : Message link to download a file</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatForwardMessage</name>
<message>

View file

@ -550,6 +550,19 @@ Serverwebbadressen är inte konfigurerad.</translation>
<extra-Context>%1 is someone. The state is that the message hasn&apos;t been delivered because of an error.</extra-Context>
</message>
</context>
<context>
<name>ChatFileMessage</name>
<message>
<source>fileTransferCancel</source>
<extracomment>&apos;Cancel&apos; : Message link to cancel a transfer (upload/download)</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>fileTransferDownload</source>
<extracomment>&apos;Download&apos; : Message link to download a file</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatForwardMessage</name>
<message>

View file

@ -549,6 +549,19 @@ Sunucu url&apos;si yapılandırılmadı.</translation>
<extra-Context>%1 is someone. The state is that the message hasn&apos;t been delivered because of an error.</extra-Context>
</message>
</context>
<context>
<name>ChatFileMessage</name>
<message>
<source>fileTransferCancel</source>
<extracomment>&apos;Cancel&apos; : Message link to cancel a transfer (upload/download)</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>fileTransferDownload</source>
<extracomment>&apos;Download&apos; : Message link to download a file</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatForwardMessage</name>
<message>

View file

@ -551,6 +551,19 @@
<extra-Context>%1 is someone. The state is that the message hasn&apos;t been delivered because of an error.</extra-Context>
</message>
</context>
<context>
<name>ChatFileMessage</name>
<message>
<source>fileTransferCancel</source>
<extracomment>&apos;Cancel&apos; : Message link to cancel a transfer (upload/download)</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>fileTransferDownload</source>
<extracomment>&apos;Download&apos; : Message link to download a file</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatForwardMessage</name>
<message>

View file

@ -549,6 +549,19 @@
<extra-Context>%1 is someone. The state is that the message hasn&apos;t been delivered because of an error.</extra-Context>
</message>
</context>
<context>
<name>ChatFileMessage</name>
<message>
<source>fileTransferCancel</source>
<extracomment>&apos;Cancel&apos; : Message link to cancel a transfer (upload/download)</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>fileTransferDownload</source>
<extracomment>&apos;Download&apos; : Message link to download a file</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatForwardMessage</name>
<message>

View file

@ -218,6 +218,7 @@
<file>ui/modules/Common/Image/Icon.qml</file>
<file>ui/modules/Common/Image/RoundedImage.qml</file>
<file>ui/modules/Common/Indicators/MediaProgressBar.qml</file>
<file>ui/modules/Common/Indicators/RoundProgressBar.qml</file>
<file>ui/modules/Common/Indicators/VuMeter.qml</file>
<file>ui/modules/Common/Menus/ApplicationMenuEntry.qml</file>
<file>ui/modules/Common/Menus/ApplicationMenu.qml</file>
@ -270,6 +271,7 @@
<file>ui/modules/Common/Styles/Form/Tab/TabContainerStyle.qml</file>
<file>ui/modules/Common/Styles/Form/TransparentTextInputStyle.qml</file>
<file>ui/modules/Common/Styles/Indicators/MediaProgressBarStyle.qml</file>
<file>ui/modules/Common/Styles/Indicators/RoundProgressBarStyle.qml</file>
<file>ui/modules/Common/Styles/Indicators/VuMeterStyle.qml</file>
<file>ui/modules/Common/Styles/Menus/ApplicationMenuStyle.qml</file>
<file>ui/modules/Common/Styles/Menus/DropDownStaticMenuStyle.qml</file>

View file

@ -234,10 +234,11 @@ void ContentModel::downloadFile(){
case LinphoneEnums::ChatMessageStateDisplayed:
case LinphoneEnums::ChatMessageStateFileTransferDone:
break;
case LinphoneEnums::ChatMessageStateFileTransferInProgress:
return;
default:
qWarning() << QStringLiteral("Wrong message state when requesting downloading, state=%1.").arg(mChatMessageModel->getState());
}
}
bool soFarSoGood;
QString filename = getName();//mFileTransfertContent->getName();
const QString safeFilePath = Utils::getSafeFilePath(
@ -261,6 +262,15 @@ void ContentModel::downloadFile(){
qWarning() << QStringLiteral("Unable to download file of entry %1.").arg(filename);
}
}
void ContentModel::cancelDownloadFile(){
if(mChatMessageModel && mChatMessageModel->getChatMessage()) {
if(mChatMessageModel->isOutgoing() ){
mChatMessageModel->deleteEvent();// Uploading is cancelling : Delete event to have clean history.
emit mChatMessageModel->remove(mChatMessageModel);
}else
mChatMessageModel->getChatMessage()->cancelFileTransfer();
}
}
void ContentModel::openFile (bool showDirectory) {
if (mChatMessageModel && ((!mWasDownloaded && !mChatMessageModel->isOutgoing()) || mContent->getFilePath() == "")) {
@ -268,9 +278,13 @@ void ContentModel::openFile (bool showDirectory) {
}else{
QFileInfo info( Utils::coreStringToAppString(mContent->getFilePath()));
showDirectory = showDirectory || !info.exists();
QDesktopServices::openUrl(
if(!QDesktopServices::openUrl(
QUrl(QStringLiteral("file:///%1").arg(showDirectory ? info.absolutePath() : info.absoluteFilePath()))
) && !showDirectory){
QDesktopServices::openUrl(
QUrl(QStringLiteral("file:///%1").arg(info.absolutePath()))
);
}
}
}

View file

@ -78,6 +78,7 @@ public:
void removeDownloadedFile();
Q_INVOKABLE void downloadFile();
Q_INVOKABLE void cancelDownloadFile();
Q_INVOKABLE void openFile (bool showDirectory = false);

View file

@ -126,6 +126,10 @@ class ColorListModel : public ProxyListModel {
ADD_COLOR("telkeypad_bg", "#4D5B66", "Background for phone keypad")
ADD_COLOR("telkeypad_fg", "#E4E4E4", "Foreground for phone keypad")
ADD_COLOR("telkeypad_h", "#B1B1B1", "Foreground for phone keypad")
ADD_COLOR("progress_bg", "black", "Background of round progress bar")
ADD_COLOR("progress_remaining_fg", "white", "Remaining progression color")
// Keywords: 'mKeywordsMap'
// s=standard, ma=main, l=list, sc=screen, me=menu

View file

@ -0,0 +1,85 @@
import QtQuick 2.15
import QtQuick.Controls 2.2
import QtQuick.Shapes 1.15
import Units 1.0
import Common.Styles 1.0
ProgressBar{
id: mainItem
property string text: value + '%'
implicitHeight: 35
implicitWidth: 35
to: 100
value: 0
background: Rectangle {
color: RoundProgressBarStyle.backgroundColor
radius: width
}
Timer{
id: animationTest
repeat: true
onTriggered: value = (value + 1) % to
interval: 5
}
contentItem:
Item{
Shape {
id: shape
anchors.fill: parent
anchors.margins: RoundProgressBarStyle.borderWidth
property real progressionRadius : Math.min(shape.width / 2, shape.height / 2) - RoundProgressBarStyle.progressionWidth / 2
layer.enabled: true
layer.samples: 8
layer.smooth: true
vendorExtensionsEnabled: false
ShapePath {
id: pathDial
strokeColor: RoundProgressBarStyle.progressRemainColor
fillColor: 'transparent'
strokeWidth: RoundProgressBarStyle.progressionWidth
capStyle: Qt.RoundCap
PathAngleArc {
radiusX: shape.progressionRadius
radiusY: shape.progressionRadius
centerX: shape.width / 2
centerY: shape.height / 2
startAngle: -90 // top start
sweepAngle: 360
}
}
ShapePath {
id: pathProgress
strokeColor: RoundProgressBarStyle.progressColor
fillColor: 'transparent'
strokeWidth: RoundProgressBarStyle.progressionWidth
capStyle: Qt.RoundCap
PathAngleArc {
radiusX: shape.progressionRadius
radiusY: shape.progressionRadius
centerX: shape.width / 2
centerY: shape.height / 2
startAngle: -90 // top start
sweepAngle: (360/ mainItem.to * mainItem.value)
}
}
}
Text{
anchors.centerIn: parent
text: mainItem.text
color: RoundProgressBarStyle.progressRemainColor
font.pointSize: RoundProgressBarStyle.pointSize
font.bold: true
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
}

View file

@ -0,0 +1,18 @@
pragma Singleton
import QtQml 2.2
import ColorsList 1.0
import Units 1.0
// =============================================================================
QtObject {
property string sectionName: 'RoundProgressBar'
property color backgroundColor: ColorsList.add(sectionName+'_bg', 'progress_bg').color
property color progressRemainColor: ColorsList.add(sectionName+'_remaining_fg', 'progress_remaining_fg').color
property color progressColor: ColorsList.add(sectionName+'_fg', 'i').color
property int progressionWidth : 3
property int borderWidth: 2
property int pointSize: Units.dp * 7
}

View file

@ -45,6 +45,7 @@ singleton TabButtonStyle 1.0 Form/Tab/TabButtonStyle.qml
singleton TabContainerStyle 1.0 Form/Tab/TabContainerStyle.qml
singleton MediaProgressBarStyle 1.0 Indicators/MediaProgressBarStyle.qml
singleton RoundProgressBarStyle 1.0 Indicators/RoundProgressBarStyle.qml
singleton VuMeterStyle 1.0 Indicators/VuMeterStyle.qml
singleton ApplicationMenuStyle 1.0 Menus/ApplicationMenuStyle.qml

View file

@ -70,6 +70,7 @@ Icon 1.0 Image/Icon.qml
RoundedImage 1.0 Image/RoundedImage.qml
MediaProgressBar 1.0 Indicators/MediaProgressBar.qml
RoundProgressBar 1.0 Indicators/RoundProgressBar.qml
VuMeter 1.0 Indicators/VuMeter.qml
ApplicationMenu 1.0 Menus/ApplicationMenu.qml

View file

@ -50,6 +50,7 @@ Row {
readonly property bool isUploaded: chatMessageModel && chatMessageModel.state == LinphoneEnums.ChatMessageStateDelivered
readonly property bool isDelivered: chatMessageModel && chatMessageModel.state == LinphoneEnums.ChatMessageStateDeliveredToUser
readonly property bool isRead: chatMessageModel && chatMessageModel.state == LinphoneEnums.ChatMessageStateDisplayed
readonly property bool isTransferring: chatMessageModel && (chatMessageModel.state == LinphoneEnums.ChatMessageStateFileTransferInProgress || chatMessageModel.state == LinphoneEnums.ChatMessageStateInProgress )
property string thumbnail : mainRow.contentModel ? mainRow.contentModel.thumbnail : ''
color: 'transparent'
@ -137,15 +138,32 @@ Row {
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottomMargin: ChatStyle.entry.message.file.spacing
width: parent.width - ChatStyle.entry.message.file.spacing
width: parent.width - 2*ChatStyle.entry.message.file.spacing
color: ChatStyle.entry.message.file.extension.text.color
font.bold: true
font.pointSize: ChatStyle.entry.message.file.extension.text.pointSize
elide: Text.ElideRight
clip: true
text: (mainRow.contentModel?Utils.getExtension(mainRow.contentModel.name).toUpperCase():'')
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
RoundProgressBar {
id: progressBar
anchors.centerIn: parent
property int fileSize: mainRow.contentModel ? mainRow.contentModel.fileSize : 0
to: 100
value: mainRow.contentModel ? (fileSize>0 ? Math.floor(100 * mainRow.contentModel.fileOffset / fileSize) : 0) : to
visible: rectangle.isTransferring && value != 0
/* Change format? Current is %
text: if(mainRow.contentModel){
var fileSize = Utils.formatSize(mainRow.contentModel.fileSize)
return progressBar.visible
? Utils.formatSize(mainRow.contentModel.fileOffset) + '/' + fileSize
: fileSize
}else
return ''
*/
}
}
Text {
id: fileName
@ -166,15 +184,20 @@ Row {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredHeight: visible ? ChatStyle.entry.message.file.download.height : 0
text: mainRow.contentModel ? 'Download ('+Utils.formatSize(mainRow.contentModel.fileSize)+')' : ''
//: 'Cancel' : Message link to cancel a transfer (upload/download)
text: mainRow.contentModel ? rectangle.isTransferring ? qsTr('fileTransferCancel')
//: 'Download' : Message link to download a file
: qsTr('fileTransferDownload') +' ('+Utils.formatSize(mainRow.contentModel.fileSize)+')'
: ''
font.underline: true
font.pointSize: ChatStyle.entry.message.file.download.pointSize
color:ChatStyle.entry.message.file.extension.text.color
visible: !progressBar.visible && (mainRow.contentModel? !mainRow.contentModel.wasDownloaded : false)
visible: (mainRow.contentModel? (!mainItem.isOutgoing && !mainRow.contentModel.wasDownloaded) || rectangle.isTransferring : false)
horizontalAlignment: Qt.AlignCenter
verticalAlignment: Qt.AlignCenter
}
}
}
}
Loader {
@ -237,66 +260,9 @@ Row {
}
]
}
// ---------------------------------------------------------------------
// Upload or file status.
// ---------------------------------------------------------------------
Item{
anchors.left: thumbnailProvider.right
anchors.right: parent.right
anchors.bottom: thumbnailProvider.bottom
anchors.top: thumbnailProvider.top
anchors.leftMargin: ChatStyle.entry.message.file.spacing
Column {
anchors.fill: parent
spacing: ChatStyle.entry.message.file.status.spacing
ProgressBar {
id: progressBar
height: ChatStyle.entry.message.file.status.bar.height
width: visible ? parent.width : 0
to: (mainRow.contentModel ? mainRow.contentModel.fileSize : 0)
value: mainRow.contentModel ? mainRow.contentModel.fileOffset || to : to
visible: value != to
background: Rectangle {
color: ChatStyle.entry.message.file.status.bar.background.color
radius: ChatStyle.entry.message.file.status.bar.radius
}
contentItem: Item {
Rectangle {
color: ChatStyle.entry.message.file.status.bar.contentItem.color
height: parent.height
width: progressBar.visualPosition * parent.width
radius: ChatStyle.entry.message.file.status.bar.radius
}
}
}
/*
Text {
visible: progressBar.value != progressBar.to
color: fileName.color
elide: Text.ElideRight
font.pointSize: fileName.font.pointSize
text: {
if(mainRow.contentModel){
var fileSize = Utils.formatSize(mainRow.contentModel.fileSize)
return progressBar.visible
? Utils.formatSize(mainRow.contentModel.fileOffset) + '/' + fileSize
: fileSize
}else
return ''
}
}*/
}
}
}
MouseArea {
function handleMouseMove (mouse) {
thumbnailProvider.state = Utils.pointIsInItem(this, thumbnailProvider, mouse)
@ -308,7 +274,9 @@ Row {
visible: true
onClicked: {
if (Utils.pointIsInItem(this, thumbnailProvider, mouse)) {
if(rectangle.isTransferring)
mainRow.contentModel.cancelDownloadFile()
else if (Utils.pointIsInItem(this, thumbnailProvider, mouse)) {
mainRow.contentModel.openFile()
} else if (mainRow.contentModel && mainRow.contentModel.wasDownloaded) {
mainRow.contentModel.openFile(true)// Show directory

View file

@ -47,7 +47,7 @@ Item{
FileView{
height:mainListView.height-ChatFilePreviewStyle.filePreview.heightMargins
width: height * ChatFilePreviewStyle.filePreview.format
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenter: parent ? parent.verticalCenter : ScrollableListView.verticalCenter
anchors.verticalCenterOffset: 7
thumbnail: $modelData.thumbnail
name: $modelData.name

View file

@ -206,8 +206,7 @@ ApplicationWindow {
colorSet: MainWindowStyle.buttons.telKeyad
onClicked: telKeypad.visible = !telKeypad.visible
toggled: telKeypad.visible
}
}
ActionButton {
Layout.leftMargin: 30
isCustom: true