Improve dialer UI and format phone number

Summary:
This makes the buttons more evenly spaced and formats the number as you type!

old: {F6084821}
new (updated): {F6084822}

The plan is to bring the entire dialer page down to about half its current size to support searching through contacts as one dials a number.

Reviewers: bshah, #plasma:_mobile, mart

Reviewed By: #plasma:_mobile, mart

Subscribers: ngraham

Differential Revision: https://phabricator.kde.org/D13936
This commit is contained in:
Michael Eden 2018-07-13 17:33:28 -04:00
parent 55e692fa53
commit 9e68bc049b
12 changed files with 173 additions and 105 deletions

View file

@ -96,6 +96,3 @@ void FullScreenPanel::showEvent(QShowEvent *event)
using namespace KWayland::Client; using namespace KWayland::Client;
QQuickWindow::showEvent(event); QQuickWindow::showEvent(event);
} }
#include "fullscreenpanel.moc"

View file

@ -201,7 +201,7 @@ int ApplicationListModel::rowCount(const QModelIndex &parent) const
return m_applicationList.count(); return m_applicationList.count();
} }
void ApplicationListModel::moveRow(const QModelIndex &sourceParent, int sourceRow, const QModelIndex &destinationParent, int destinationChild) void ApplicationListModel::moveRow(const QModelIndex& /* sourceParent */, int sourceRow, const QModelIndex& /* destinationParent */, int destinationChild)
{ {
moveItem(sourceRow, destinationChild); moveItem(sourceRow, destinationChild);
} }
@ -249,7 +249,7 @@ void ApplicationListModel::runApplication(const QString &storageId)
KService::Ptr service = KService::serviceByStorageId(storageId); KService::Ptr service = KService::serviceByStorageId(storageId);
KRun::run(*service, QList<QUrl>(), 0); KRun::runService(*service, QList<QUrl>(), 0);
} }
QStringList ApplicationListModel::appOrder() const QStringList ApplicationListModel::appOrder() const
@ -272,5 +272,3 @@ void ApplicationListModel::setAppOrder(const QStringList &order)
} }
emit appOrderChanged(); emit appOrderChanged();
} }
#include "applicationlistmodel.moc"

View file

@ -29,10 +29,6 @@ Item {
property alias numberEntryText: status.text property alias numberEntryText: status.text
function addNumber(number) {
status.text = status.text + number
}
Rectangle { Rectangle {
width: parent.width / 2 width: parent.width / 2
x: parent.width / 4 x: parent.width / 4
@ -59,16 +55,13 @@ Item {
margins: units.largeSpacing margins: units.largeSpacing
} }
PlasmaComponents.Label { PhoneNumberInput {
id: status id: status
Layout.fillWidth: true
Layout.minimumHeight: parent.height / 6
Layout.maximumHeight: Layout.minimumHeight
horizontalAlignment: Qt.AlignRight Layout.fillWidth: true
verticalAlignment: Qt.AlignVCenter Layout.minimumHeight: units.gridUnit * 3.5
font.pointSize: 1024 Layout.maximumHeight: Layout.minimumHeight
fontSizeMode: Text.Fit font.pointSize: 30
} }
Dialpad { Dialpad {
@ -76,7 +69,7 @@ Item {
Layout.fillHeight: true Layout.fillHeight: true
callback: function (string) { callback: function (string) {
addNumber(string); status.append(string)
} }
pressedCallback: function (string) { pressedCallback: function (string) {
//TODO //TODO

View file

@ -9,6 +9,7 @@
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details * GNU Library General Public License for more details
* *
@ -23,22 +24,16 @@ import QtQuick.Layouts 1.1
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.components 2.0 as PlasmaComponents
PlasmaComponents.Label { Item {
id: root
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
//This is 0 to override the Label default height that would cause a binding loop property string text
height: 0 property string sub
horizontalAlignment: Text.AlignHCenter property string display
verticalAlignment: Text.AlignTop property string subdisplay
font.pointSize: 21 //anything higher for some reason makes number 4 not rendered property bool special: false
minimumPointSize: 8
fontSizeMode: Text.VerticalFit
property alias sub: longHold.text
property var callback
property var pressedCallback
property var releasedCallback
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
@ -57,68 +52,61 @@ PlasmaComponents.Label {
MouseArea { MouseArea {
id: mouse id: mouse
anchors.fill: parent anchors.fill: parent
onPressed: { onPressed: {
if (pressedCallback) { if (pad.pressedCallback) {
pressedCallback(parent.text);
} else if (pad.pressedCallback) {
pad.pressedCallback(parent.text); pad.pressedCallback(parent.text);
} }
} }
onReleased: { onReleased: {
if (releasedCallback) { if (pad.releasedCallback) {
releasedCallback(parent.text);
} else if (pad.releasedCallback) {
pad.releasedCallback(parent.text); pad.releasedCallback(parent.text);
} }
} }
onCanceled: { onCanceled: {
if (releasedCallback) { if (pad.releasedCallback) {
releasedCallback(parent.text);
} else if (pad.releasedCallback) {
pad.releasedCallback(parent.text); pad.releasedCallback(parent.text);
} }
} }
onClicked: { onClicked: {
if (callback) { if (pad.callback) {
callback(parent.text);
} else if (pad.callback) {
pad.callback(parent.text); pad.callback(parent.text);
} }
} }
onPressAndHold: { onPressAndHold: {
var text; var text = parent.sub.length > 0 ? parent.sub : parent.text
if (longHold.visible) { if (pad.callback && text.length === 1) {
text = longHold.text;
} else {
text = parent.text;
}
if (text.length > 1) {
return;
}
if (callback) {
callback(text);
} else if (pad.callback) {
pad.callback(text); pad.callback(text);
} }
} }
} }
ColumnLayout {
spacing: -5
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
PlasmaComponents.Label {
id: main
text: root.display || root.text
opacity: special? 0.4 : 1.0
// anything higher for some reason makes number 4 not rendered
font.pointSize: 30
fontSizeMode: Text.VerticalFit
Layout.minimumWidth: parent.width
horizontalAlignment: Text.AlignHCenter
}
PlasmaComponents.Label { PlasmaComponents.Label {
id: longHold id: longHold
anchors {
bottom: parent.bottom
}
height: parent.height * 0.4
width: parent.width
verticalAlignment: Text.AlignBottom
horizontalAlignment: Text.AlignHCenter
visible: text.length > 0
opacity: 0.4
text: root.subdisplay || root.sub
opacity: 0.4
font.pointSize: 16
fontSizeMode: Text.VerticalFit fontSizeMode: Text.VerticalFit
Layout.minimumWidth: parent.width
horizontalAlignment: Text.AlignHCenter
}
} }
} }

View file

@ -56,7 +56,7 @@ Item {
id: icon id: icon
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: height width: height
height: buttonRoot.height * 0.6 height: units.gridUnit * 3.5
} }
PlasmaComponents.Label { PlasmaComponents.Label {
id: label id: label

View file

@ -26,13 +26,13 @@ import org.kde.plasma.components 2.0 as PlasmaComponents
GridLayout { GridLayout {
id: pad id: pad
columns: 3 columns: 3
rowSpacing: 10
columnSpacing: 10
property var callback property var callback
property var pressedCallback property var pressedCallback
property var releasedCallback property var releasedCallback
property int buttonHeight: parent.height / 6
DialerButton { id: one; text: "1" } DialerButton { id: one; text: "1" }
DialerButton { text: "2"; sub: "ABC" } DialerButton { text: "2"; sub: "ABC" }
DialerButton { text: "3"; sub: "DEF" } DialerButton { text: "3"; sub: "DEF" }
@ -45,15 +45,18 @@ GridLayout {
DialerButton { text: "8"; sub: "TUV" } DialerButton { text: "8"; sub: "TUV" }
DialerButton { text: "9"; sub: "WXYZ" } DialerButton { text: "9"; sub: "WXYZ" }
DialerButton { text: "*"; } DialerButton { display: ""; text: "*"; special: true; }
DialerButton { text: "0"; sub: "+"; } DialerButton { text: "0"; subdisplay: ""; sub: "+"; }
DialerButton { text: "#" } DialerButton { display: ""; text: "#"; special: true; }
Item {
Layout.fillWidth: true
Layout.fillHeight: true
}
DialerIconButton { DialerIconButton {
id: callButton id: callButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.maximumHeight: buttonHeight Layout.fillHeight: true
Layout.minimumHeight: Layout.maximumHeight
enabled: status.text.length > 0 enabled: status.text.length > 0
opacity: enabled ? 1 : 0.5 opacity: enabled ? 1 : 0.5
@ -64,19 +67,6 @@ GridLayout {
} }
Item { Item {
Layout.fillWidth: true Layout.fillWidth: true
} Layout.fillHeight: true
DialerIconButton {
Layout.fillWidth: true
Layout.maximumHeight: buttonHeight
Layout.minimumHeight: Layout.maximumHeight
enabled: status.text.length > 0
opacity: enabled ? 1 : 0.5
source: "edit-clear"
callback: function(text) {
if (status.text.length > 0) {
status.text = status.text.substr(0, status.text.length - 1);
}
}
} }
} }

View file

@ -0,0 +1,62 @@
import QtQuick 2.0
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.1
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
PlasmaComponents.TextField {
id: root
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignBottom
style: TextFieldStyle {
background: Rectangle {
opacity: 0
}
}
signal append(string digit)
onAppend: {
text += digit
}
onTextChanged: {
text = dialerUtils.formatNumber(text);
}
// TODO: search through contacts while typing
Row {
anchors {
right: parent.right
rightMargin: 6
verticalCenter: parent.verticalCenter
}
PlasmaCore.IconItem {
id: delBtn
// ltr confusingly refers to the direction of the arrow in the icon,
// not the text direction which it should be used in.
source: LayoutMirroring.enabled ?
"edit-clear-locationbar-ltr" : "edit-clear-locationbar-rtl"
height: Math.max(root.height * 0.8, units.iconSizes.small)
width: height
opacity: (root.length > 0 && root.enabled) ? 1 : 0
visible: opacity > 0
Behavior on opacity {
NumberAnimation {
duration: units.longDuration
easing.type: Easing.InOutQuad
}
}
MouseArea {
anchors.fill: parent
onClicked: {
if (text.length > 0) {
text = text.slice(0, -1);
}
}
}
}
}
}

View file

@ -27,5 +27,3 @@ void KPeopleHelperPlugin::registerTypes(const char *uri)
qmlRegisterType<KPeopleHelper>(uri, 1, 0, "KPeopleHelper"); qmlRegisterType<KPeopleHelper>(uri, 1, 0, "KPeopleHelper");
} }
#include "kpeoplehelperplugin.moc"

View file

@ -11,8 +11,10 @@ add_executable(plasmaphonedialer ${plasmaphonedialer_SRCS})
target_compile_definitions(plasmaphonedialer PRIVATE -DPROJECT_VERSION="${PROJECT_VERSION}") target_compile_definitions(plasmaphonedialer PRIVATE -DPROJECT_VERSION="${PROJECT_VERSION}")
#find_package(ActiveApp REQUIRED) #find_package(ActiveApp REQUIRED)
find_library(phonenumber REQUIRED)
target_link_libraries(plasmaphonedialer target_link_libraries(plasmaphonedialer
phonenumber
Qt5::Gui Qt5::Gui
Qt5::Quick Qt5::Quick
Qt5::Widgets Qt5::Widgets

View file

@ -20,7 +20,6 @@
#include <QDebug> #include <QDebug>
#include <KLocalizedString>
#include <TelepathyQt/PendingOperation> #include <TelepathyQt/PendingOperation>
#include <TelepathyQt/PendingChannelRequest> #include <TelepathyQt/PendingChannelRequest>
#include <TelepathyQt/PendingReady> #include <TelepathyQt/PendingReady>
@ -29,6 +28,9 @@
#include <TelepathyQt/Types> #include <TelepathyQt/Types>
#include <TelepathyQt/ContactManager> #include <TelepathyQt/ContactManager>
#include "phonenumbers/phonenumberutil.h"
#include "phonenumbers/asyoutypeformatter.h"
DialerUtils::DialerUtils(const Tp::AccountPtr &simAccount, QObject *parent) DialerUtils::DialerUtils(const Tp::AccountPtr &simAccount, QObject *parent)
: QObject(parent), : QObject(parent),
m_missedCalls(0), m_missedCalls(0),
@ -77,6 +79,33 @@ QString DialerUtils::callState() const
return m_callState; return m_callState;
} }
const QString DialerUtils::formatNumber(const QString& number)
{
using namespace ::i18n::phonenumbers;
// Get formatter instance
QLocale locale;
QStringList qcountry = locale.name().split('_');
QString countrycode(qcountry.constLast());
const char* country = countrycode.toUtf8().constData();
PhoneNumberUtil* util = PhoneNumberUtil::GetInstance();
AsYouTypeFormatter* formatter = util->PhoneNumberUtil::GetAsYouTypeFormatter(country);
// Normalize input
string stdnumber = number.toUtf8().constData();
util->NormalizeDiallableCharsOnly(&stdnumber);
// Format
string formatted;
formatter->Clear();
for (char& c : stdnumber) {
formatter->InputDigit(c, &formatted);
}
delete formatter;
return QString::fromStdString(formatted);
}
void DialerUtils::setCallState(const QString &state) void DialerUtils::setCallState(const QString &state)
{ {
if (m_callState != state) { if (m_callState != state) {

View file

@ -58,6 +58,7 @@ public:
Q_INVOKABLE void resetMissedCalls(); Q_INVOKABLE void resetMissedCalls();
Q_INVOKABLE void dial(const QString &number); Q_INVOKABLE void dial(const QString &number);
Q_INVOKABLE const QString formatNumber(const QString& number);
Q_SIGNALS: Q_SIGNALS:
void missedCallsActionTriggered(); void missedCallsActionTriggered();
@ -77,9 +78,9 @@ private:
int m_missedCalls; int m_missedCalls;
QString m_callState; QString m_callState;
Tp::AccountPtr m_simAccount; Tp::AccountPtr m_simAccount;
QString m_callContactAlias;
QString m_callContactNumber; QString m_callContactNumber;
uint m_callDuration; uint m_callDuration;
QString m_callContactAlias;
bool m_isIncomingCall; bool m_isIncomingCall;
}; };

View file

@ -52,25 +52,35 @@
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{ {
// TODO: print it on stdout too?
QFile file(QDir::homePath() + "/dialer.log"); QFile file(QDir::homePath() + "/dialer.log");
bool opened = file.open(QIODevice::WriteOnly | QIODevice::Append); bool opened = file.open(QIODevice::WriteOnly | QIODevice::Append);
Q_ASSERT(opened); Q_ASSERT(opened);
QTextStream out(&file); QString strout;
QTextStream out(&strout);
out << QTime::currentTime().toString("hh:mm:ss.zzz "); out << QTime::currentTime().toString("hh:mm:ss.zzz ");
out << context.function << ":" << context.line << " "; out << context.function << ":" << context.line << " ";
switch (type) { switch (type) {
case QtDebugMsg: out << "DBG"; break; case QtDebugMsg: out << "DBG"; break;
case QtInfoMsg: out << "NFO"; break;
case QtWarningMsg: out << "WRN"; break; case QtWarningMsg: out << "WRN"; break;
case QtCriticalMsg: out << "CRT"; break; case QtCriticalMsg: out << "CRT"; break;
case QtFatalMsg: out << "FTL"; break; case QtFatalMsg: out << "FTL"; break;
} }
out << " " << msg << '\n'; out << " " << msg << '\n';
// Write to log file
QTextStream fileout(&file);
fileout << strout;
out.flush(); out.flush();
// Write to stdout
QTextStream console(stdout);
console << strout;
console.flush();
} }
int main(int argc, char **argv) int main(int argc, char **argv)