diff --git a/CMakeLists.txt b/CMakeLists.txt index b37f3ce..6508cc0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,61 +1,61 @@ project(plasma-phone-components) # minimal requirements cmake_minimum_required (VERSION 2.8.12 FATAL_ERROR) set (QT_MIN_VERSION "5.2.0") set(KF5_MIN_VERSION "5.0.0") set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_CXX_STANDARD 14) find_package(ECM 5.41.0 REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_SOURCE_DIR}/cmake) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings) include(ECMOptionalAddSubdirectory) include(ECMInstallIcons) include(ECMSetupVersion) include(ECMMarkNonGuiExecutable) include(ECMGenerateHeaders) include(GenerateExportHeader) include(FeatureSummary) -find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED Core Gui Widgets Qml Quick Test) +find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED Core Gui Widgets Qml Quick Test Sql) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Plasma Service Declarative I18n KIO People) find_package(KF5 REQUIRED COMPONENTS PlasmaQuick DBusAddons Notifications) find_package(TelepathyQt5 REQUIRED) find_package(KF5Wayland CONFIG) set_package_properties(KF5Wayland PROPERTIES TYPE REQUIRED PURPOSE "Required for interacting with the compositor") # torch find_package(GStreamer 1.1.90 REQUIRED) find_package(GLIB2 REQUIRED) find_package(GObject REQUIRED) include(CheckIncludeFiles) plasma_install_package(look-and-feel org.kde.plasma.phone look-and-feel) plasma_install_package(shell org.kde.plasma.phone shells) install(DIRECTORY wallpaper/ DESTINATION "${WALLPAPER_INSTALL_DIR}/org.kde.plasma.phone.lockers") install( DIRECTORY kwinmultitasking/ DESTINATION ${DATA_INSTALL_DIR}/kwin/scripts/org.kde.phone.multitasking ) install( FILES kwinmultitasking/metadata.desktop DESTINATION ${SERVICES_INSTALL_DIR} RENAME kwin-script-org.kde.phone.multitasking.desktop ) install( DIRECTORY qtvirtualkeyboardplugin/ DESTINATION ${KDE_INSTALL_QMLDIR}/QtQuick/VirtualKeyboard/Styles/Plasma ) add_subdirectory(bin) add_subdirectory(applets) add_subdirectory(containments) add_subdirectory(dialer) add_subdirectory(sounds) #add_subdirectory(touchscreentest) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/dialer/src/CMakeLists.txt b/dialer/src/CMakeLists.txt index 6f5cd88..ef5aaa5 100644 --- a/dialer/src/CMakeLists.txt +++ b/dialer/src/CMakeLists.txt @@ -1,34 +1,36 @@ set(plasmaphonedialer_SRCS main.cpp dialerutils.cpp call-handler.cpp + callhistorymodel.cpp call-manager.cpp resources.qrc ) add_executable(plasmaphonedialer ${plasmaphonedialer_SRCS}) target_compile_definitions(plasmaphonedialer PRIVATE -DPROJECT_VERSION="${PROJECT_VERSION}") find_package(PhoneNumber COMPONENTS PhoneNumber REQUIRED) target_link_libraries(plasmaphonedialer PhoneNumber::PhoneNumber Qt5::Gui Qt5::Quick Qt5::Widgets + Qt5::Sql KF5::Declarative KF5::I18n KF5::QuickAddons KF5::DBusAddons KF5::Notifications ${TELEPATHY_QT5_LIBRARIES} ) install(TARGETS plasmaphonedialer ${INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES plasma_dialer.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFY5RCDIR}) configure_file(org.freedesktop.Telepathy.Client.Plasma.Dialer.service.in org.freedesktop.Telepathy.Client.Plasma.Dialer.service) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.Telepathy.Client.Plasma.Dialer.service DESTINATION ${DBUS_SERVICES_INSTALL_DIR}) install(FILES Plasma.Dialer.client DESTINATION ${SHARE_INSTALL_PREFIX}/telepathy/clients/) diff --git a/dialer/src/callhistorymodel.cpp b/dialer/src/callhistorymodel.cpp new file mode 100644 index 0000000..97442eb --- /dev/null +++ b/dialer/src/callhistorymodel.cpp @@ -0,0 +1,149 @@ +/* + Copyright (C) 2019 Nicolas Fella + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ +#include "callhistorymodel.h" + +#include +#include +#include +#include +#include + +CallHistoryModel::CallHistoryModel(QObject *parent) + : QAbstractListModel(parent) + , m_db(QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), QStringLiteral("calldb"))) +{ + m_db.setDatabaseName(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "plasmaphonedialerdb.sqlite"); + bool open = m_db.open(); + + if (!open) { + qWarning() << "Could not open call database" << m_db.lastError(); + } + + QSqlQuery createTable(m_db); + createTable.exec(QStringLiteral("CREATE TABLE IF NOT EXISTS History(id INTEGER PRIMARY KEY AUTOINCREMENT, number TEXT, time DATETIME, duration INTEGER, callType INTEGER)")); + + QSqlQuery fetchCalls(m_db); + fetchCalls.exec(QStringLiteral("SELECT id, number, time, duration, callType FROM History")); + + beginResetModel(); + while (fetchCalls.next()) { + CallData call; + call.id = fetchCalls.value(0).toString(); + call.number = fetchCalls.value(1).toString(); + call.time = QDateTime::fromMSecsSinceEpoch(fetchCalls.value(2).toInt()); + call.duration = fetchCalls.value(3).toInt(); + call.callType = fetchCalls.value(4).toInt(); + + m_calls.append(call); + } + endResetModel(); +} + +void CallHistoryModel::addCall(QString number, int duration, int type) +{ + beginInsertRows(QModelIndex(), m_calls.size(), m_calls.size()); + QSqlQuery putCall(m_db); + putCall.prepare(QStringLiteral("INSERT INTO History (number, time, duration, callType) VALUES (:number, :time, :duration, :callType)")); + putCall.bindValue(":number", number); + putCall.bindValue(":time", QDateTime::currentDateTime().toMSecsSinceEpoch()); + putCall.bindValue(":duration", duration); + putCall.bindValue(":callType", type); + putCall.exec(); + + CallData data; + data.id = putCall.lastInsertId().toString(); + data.number = number; + data.duration = duration; + data.time = QDateTime::currentDateTime(); + data.callType = type; + + m_calls.append(data); + + endInsertRows(); +} + +void CallHistoryModel::clear() +{ + beginResetModel(); + + QSqlQuery clearCalls(m_db); + clearCalls.exec(QStringLiteral("DELETE FROM History")); + m_calls.clear(); + + endResetModel(); +} + +QVariant CallHistoryModel::data(const QModelIndex& index, int role) const +{ + int row = index.row(); + + switch (role) { + case Roles::PhoneNumberRole: + return m_calls[row].number; + case Roles::CallTypeRole: + return m_calls[row].callType; + case Roles::DurationRole: + return m_calls[row].duration; + case Roles::TimeRole: + return m_calls[row].time; + case Roles::IdRole: + return m_calls[row].id; + } + return {}; +} + +int CallHistoryModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_calls.size(); +} + +QHash CallHistoryModel::roleNames() const +{ + QHash roleNames; + roleNames[PhoneNumberRole] = "number"; + roleNames[CallTypeRole] = "time"; + roleNames[DurationRole] = "duration"; + roleNames[TimeRole] = "callType"; + roleNames[IdRole] = "dbid"; + + return roleNames; +} + +bool CallHistoryModel::removeRows(int row, int count, const QModelIndex &parent) +{ + Q_UNUSED(count) + + beginRemoveRows(parent, row, row); + QSqlQuery remove(m_db); + remove.prepare(QStringLiteral("DELETE FROM History WHERE id=:id")); + remove.bindValue(":id", m_calls[row].id); + remove.exec(); + + endRemoveRows(); + return true; +} + +void CallHistorySortFilterModel::remove(int index) +{ + QSortFilterProxyModel::removeRow(index); +} + +void CallHistorySortFilterModel::sort(int column, Qt::SortOrder order) +{ + QSortFilterProxyModel::sort(column, order); +} diff --git a/dialer/src/callhistorymodel.h b/dialer/src/callhistorymodel.h new file mode 100644 index 0000000..711acce --- /dev/null +++ b/dialer/src/callhistorymodel.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2019 Nicolas Fella + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ +#pragma once + +#include +#include +#include +#include +#include + +struct CallData { + QString id; + QString number; + QDateTime time; + int duration; + int callType; +}; + +class CallHistoryModel : public QAbstractListModel +{ + Q_OBJECT +public: + + CallHistoryModel(QObject *parent = nullptr); + + enum Roles { + PhoneNumberRole = Qt::UserRole + 1, + DurationRole, + TimeRole, + CallTypeRole, + IdRole + }; + Q_ENUM(Roles) + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QHash roleNames() const override; + + Q_INVOKABLE void addCall(QString number, int duration, int type); + Q_INVOKABLE void clear(); + + bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; + +private: + QSqlDatabase m_db; + QVector m_calls; +}; + +class CallHistorySortFilterModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + Q_INVOKABLE void remove(int index); + Q_INVOKABLE void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; +}; diff --git a/dialer/src/main.cpp b/dialer/src/main.cpp index 905f1e4..4f34193 100644 --- a/dialer/src/main.cpp +++ b/dialer/src/main.cpp @@ -1,214 +1,218 @@ /* * Copyright 2015 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "dialerutils.h" #include "call-handler.h" +#include "callhistorymodel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { QFile file(QDir::homePath() + "/dialer.log"); bool opened = file.open(QIODevice::WriteOnly | QIODevice::Append); Q_ASSERT(opened); QString strout; QTextStream out(&strout); out << QTime::currentTime().toString("hh:mm:ss.zzz "); out << context.function << ":" << context.line << " "; switch (type) { case QtDebugMsg: out << "DBG"; break; case QtInfoMsg: out << "NFO"; break; case QtWarningMsg: out << "WRN"; break; case QtCriticalMsg: out << "CRT"; break; case QtFatalMsg: out << "FTL"; break; } out << " " << msg << '\n'; // Write to log file QTextStream fileout(&file); fileout << strout; out.flush(); // Write to stdout QTextStream console(stdout); console << strout; console.flush(); } int main(int argc, char **argv) { qInstallMessageHandler(myMessageOutput); QCommandLineParser parser; QApplication app(argc, argv); const QString description = i18n("Plasma Phone Dialer"); const char version[] = PROJECT_VERSION; // app.setQuitOnLastWindowClosed(false); app.setApplicationVersion(version); app.setOrganizationDomain("kde.org"); KDBusService service(KDBusService::Unique); parser.addVersionOption(); parser.addHelpOption(); parser.setApplicationDescription(description); QCommandLineOption daemonOption(QStringList() << QStringLiteral("d") << QStringLiteral("daemon"), i18n("Daemon mode. run without displaying anything.")); parser.addPositionalArgument("number", i18n("Call the given number")); parser.addOption(daemonOption); parser.process(app); + qmlRegisterType("org.kde.plasma.dialer", 1, 0, "CallHistoryModel"); + qmlRegisterType("org.kde.plasma.dialer", 1, 0, "CallHistorySortFilterModel"); + Tp::registerTypes(); Tp::AccountFactoryPtr accountFactory = Tp::AccountFactory::create(QDBusConnection::sessionBus(), Tp::Features() << Tp::Account::FeatureCore ); Tp::ConnectionFactoryPtr connectionFactory = Tp::ConnectionFactory::create(QDBusConnection::sessionBus(), Tp::Features() << Tp::Connection::FeatureCore << Tp::Connection::FeatureSelfContact << Tp::Connection::FeatureConnected ); Tp::ChannelFactoryPtr channelFactory = Tp::ChannelFactory::create(QDBusConnection::sessionBus()); channelFactory->addCommonFeatures(Tp::Channel::FeatureCore); channelFactory->addFeaturesForCalls(Tp::Features() << Tp::CallChannel::FeatureContents << Tp::CallChannel::FeatureCallState << Tp::CallChannel::FeatureCallMembers << Tp::CallChannel::FeatureLocalHoldState ); // channelFactory->addFeaturesForTextChats(Tp::Features() << Tp::TextChannel::FeatureMessageQueue // << Tp::TextChannel::FeatureMessageSentSignal // << Tp::TextChannel::FeatureChatState // << Tp::TextChannel::FeatureMessageCapabilities); Tp::ContactFactoryPtr contactFactory = Tp::ContactFactory::create(Tp::Features() << Tp::Contact::FeatureAlias << Tp::Contact::FeatureAvatarData ); Tp::ClientRegistrarPtr registrar = Tp::ClientRegistrar::create(accountFactory, connectionFactory, channelFactory, contactFactory); QEventLoop loop; Tp::AccountManagerPtr manager = Tp::AccountManager::create(); Tp::PendingReady *ready = manager->becomeReady(); QObject::connect(ready, &Tp::PendingReady::finished, &loop, &QEventLoop::quit); loop.exec(QEventLoop::ExcludeUserInputEvents); Tp::AccountPtr simAccount; const Tp::AccountSetPtr accountSet = manager->validAccounts(); for (const Tp::AccountPtr &account : accountSet->accounts()) { static const QStringList supportedProtocols = { QLatin1String("ofono"), QLatin1String("tel"), }; if (supportedProtocols.contains(account->protocolName())) { simAccount = account; break; } } if (simAccount.isNull()) { qCritical() << "Unable to get SIM account"; return -1; } QQmlApplicationEngine engine; engine.rootContext()->setContextObject(new KLocalizedContext(&engine)); auto *dialerUtils = new DialerUtils(simAccount); engine.rootContext()->setContextProperty("dialerUtils", QVariant::fromValue(dialerUtils)); engine.rootContext()->setContextProperty("commandlineArguments", parser.positionalArguments()); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); Tp::SharedPtr callHandler(new CallHandler(dialerUtils)); registrar->registerClient(Tp::AbstractClientPtr::dynamicCast(callHandler), "Plasma.Dialer"); KAboutData aboutData("dialer", i18n("Dialer"), "0.9", i18n("Plasma phone dialer"), KAboutLicense::GPL); aboutData.setDesktopFileName("org.kde.phone.dialer"); KAboutData::setApplicationData(aboutData); QWindow *window = qobject_cast(engine.rootObjects()[0]); Q_ASSERT(window); QObject::connect(&service, &KDBusService::activateRequested, [=](const QStringList &arguments, const QString &workingDirectory) { Q_UNUSED(workingDirectory); window->show(); window->requestActivate(); if (arguments.length() > 0) { QString numberArg = arguments[1]; if (numberArg.startsWith("call://")) { numberArg = numberArg.mid(7); } dialerUtils->dial(numberArg); } }); if (!parser.isSet(daemonOption)) { window->show(); window->requestActivate(); } if (!parser.positionalArguments().isEmpty()) { QString numberArg = parser.positionalArguments().first(); if (numberArg.startsWith("call://")) { numberArg = numberArg.mid(7); } qWarning() << "Calling" << numberArg; dialerUtils->dial(numberArg); } return app.exec(); } diff --git a/dialer/src/qml/Dialer/History.qml b/dialer/src/qml/Dialer/History.qml index 4760465..5d932f2 100644 --- a/dialer/src/qml/Dialer/History.qml +++ b/dialer/src/qml/Dialer/History.qml @@ -1,107 +1,109 @@ /* * Copyright 2015 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.4 import QtQuick.Layouts 1.1 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.extras 2.0 as PlasmaExtras +import org.kde.plasma.dialer 1.0 + Item { function secondsToTimeString(seconds) { var h = Math.floor(seconds / 3600); var m = Math.floor((seconds - (h * 3600)) / 60); var s = seconds - h * 3600 - m * 60; if(h < 10) h = '0' + h; if(m < 10) m = '0' + m; if(s < 10) s = '0' + s; return '' + h + ':' + m + ':' + s; } PlasmaComponents.Label { anchors.centerIn: parent text: i18n("No recent calls") - visible: historyModel.count == 0 + visible: view.count == 0 } ColumnLayout { anchors.fill: parent - visible: historyModel.count > 0 + visible: view.count > 0 PlasmaComponents.ToolBar { Layout.fillWidth: true tools: RowLayout { id: toolBarLayout PlasmaComponents.TabBar { tabPosition: Qt.TopEdge PlasmaComponents.TabButton { iconSource: "call-start" text: i18n("All") onCheckedChanged: { if (checked) { - filterModel.filterString = ""; + filterModel.setFilterFixedString("") } } } PlasmaComponents.TabButton { iconSource: "list-remove" text: i18n("Missed") onCheckedChanged: { if (checked) { - filterModel.filterString = "0"; + filterModel.setFilterFixedString("0") } } } } Item { Layout.fillWidth: true } PlasmaComponents.Button { text: i18n("Clear") - onClicked: clearHistory(); + onClicked: historyModel.clear() } } } PlasmaExtras.ScrollArea { Layout.fillWidth: true Layout.fillHeight: true ListView { id: view - model: PlasmaCore.SortFilterModel { + model: CallHistorySortFilterModel { id: filterModel sourceModel: historyModel - filterRole: "callType" - sortRole: "time" - sortOrder: Qt.DescendingOrder + filterRole: CallHistoryModel.CallTypeRole + sortRole: CallHistoryModel.TimeRole + Component.onCompleted: sort(0, Qt.DescendingOrder) } section { property: "date" delegate: PlasmaComponents.ListItem { id: sectionItem sectionDelegate: true PlasmaComponents.Label { text: Qt.formatDate(section, Qt.locale().dateFormat(Locale.LongFormat)); } } } delegate: HistoryDelegate {} } } } } diff --git a/dialer/src/qml/Dialer/HistoryDelegate.qml b/dialer/src/qml/Dialer/HistoryDelegate.qml index 74b3304..876fdc5 100644 --- a/dialer/src/qml/Dialer/HistoryDelegate.qml +++ b/dialer/src/qml/Dialer/HistoryDelegate.qml @@ -1,125 +1,124 @@ /* * Copyright 2015 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.4 import QtQuick.Layouts 1.1 import QtQuick.Controls 2.2 as Controls import org.kde.kirigami 2.2 as Kirigami import org.kde.plasma.components 2.0 as PlasmaComponents - Item { id: delegateParent width: view.width height: childrenRect.height Behavior on height { SpringAnimation { spring: 5; damping: 0.3 } } SequentialAnimation { id: removeAnim XAnimator { target: delegate from: delegate.x to: delegate.x > 0 ? width : -width duration: units.longDuration easing.type: Easing.InOutQuad } PropertyAnimation { target: delegateParent properties: "height" to: 0 duration: units.longDuration easing.type: Easing.InOutQuad } ScriptAction { - script: removeCallFromHistory(model.originalIndex); + script: filterModel.remove(model.index) } } XAnimator { id: resetAnim target: delegate from: delegate.x to: 0 duration: units.longDuration easing.type: Easing.InOutQuad } PlasmaComponents.ListItem { id: delegate MouseArea { width: parent.width height: childrenRect.height onClicked: call(model.number); drag.axis: Drag.XAxis drag.target: delegate onReleased: { if (drag.active) { if (delegate.x > delegate.width / 3 || delegate.x < width / -3) { removeAnim.running = true; } else { resetAnim.running = true; } } } RowLayout { width: parent.width //FIXME: ad hoc icons Kirigami.Icon { width: units.iconSizes.medium height: width source: { switch (model.callType) { case 0: return "list-remove"; case 1: return "go-down"; case 2: return "go-up"; } } } ColumnLayout { Controls.Label { text: "Name (todo)" } Controls.Label { text: model.number Layout.fillWidth: true } } ColumnLayout { Controls.Label { Layout.alignment: Qt.AlignRight text: Qt.formatTime(model.time, Qt.locale().timeFormat(Locale.ShortFormat)); } Controls.Label { Layout.alignment: Qt.AlignRight text: i18n("Duration: %1", secondsToTimeString(model.duration)); visible: model.duration > 0 } } } } } } diff --git a/dialer/src/qml/main.qml b/dialer/src/qml/main.qml index d5402ba..441c258 100644 --- a/dialer/src/qml/main.qml +++ b/dialer/src/qml/main.qml @@ -1,195 +1,121 @@ /** * Copyright 2014 Aaron Seigo * Copyright 2014 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 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 Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.3 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.1 import QtQuick.LocalStorage 2.0 import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.kirigami 2.0 as Kirigami +import org.kde.plasma.dialer 1.0 + ApplicationWindow { id: root //BEGIN PROPERTIES width: 1080 height: 800 visible: false //keep track if we were visible when ringing property bool wasVisible //was the last call an incoming one? property bool isIncoming //END PROPERTIES //BEGIN SIGNAL HANDLERS Connections { target: dialerUtils onMissedCallsActionTriggered: { root.visible = true; } onCallEnded: { var callType; if (isIncomingCall && callDuration == 0) { callType = 0; } else if (isIncomingCall && callDuration > 0) { callType = 1; } else { callType = 2; } - insertCallInHistory(callContactNumber, callDuration, callType); + historyModel.addCall(callContactNumber, callDuration, callType) } } onVisibleChanged: { //TODO //reset missed calls if the status is not STATUS_INCOMING when got visible } //END SIGNAL HANDLERS //BEGIN FUNCTIONS function call(number) { dialerUtils.dial(number); } - - function insertCallInHistory(number, duration, callType) { - //DATABSE - var db = LocalStorage.openDatabaseSync("PlasmaPhoneDialer", "1.0", "Call history of the Plasma Phone dialer", 1000000); - - db.transaction( - function(tx) { - var rs = tx.executeSql("INSERT INTO History VALUES(NULL, ?, datetime('now'), ?, ? )", [number, duration, callType]); - - var rs = tx.executeSql('SELECT * FROM History where id=?', [rs.insertId]); - - for(var i = 0; i < rs.rows.length; i++) { - var row = rs.rows.item(i); - row.date = Qt.formatDate(row.time, "yyyy-MM-dd"); - row.originalIndex = historyModel.count; - historyModel.append(row); - } - } - ) - } - - //index is historyModel row number, not db id and not sortmodel row number - function removeCallFromHistory(index) { - var item = historyModel.get(index); - - if (!item) { - return; - } - - var db = LocalStorage.openDatabaseSync("PlasmaPhoneDialer", "1.0", "Call history of the Plasma Phone dialer", 1000000); - - db.transaction( - function(tx) { - tx.executeSql("DELETE from History WHERE id=?", [item.id]); - } - ) - - historyModel.remove(index); - } - - function clearHistory() { - var db = LocalStorage.openDatabaseSync("PlasmaPhoneDialer", "1.0", "Call history of the Plasma Phone dialer", 1000000); - - db.transaction( - function(tx) { - tx.executeSql("DELETE from History"); - } - ) - - historyModel.clear(); - } - //END FUNCTIONS -//BEGIN DATABASE - Component.onCompleted: { - //DATABSE - var db = LocalStorage.openDatabaseSync("PlasmaPhoneDialer", "1.0", "Call history of the Plasma Phone dialer", 1000000); - - db.transaction( - function(tx) { - // Create the database if it doesn't already exist - //callType: whether is incoming, outgoing, unanswered - tx.executeSql('CREATE TABLE IF NOT EXISTS History(id INTEGER PRIMARY KEY AUTOINCREMENT, number TEXT, time DATETIME, duration INTEGER, callType INTEGER)'); - - var rs = tx.executeSql('SELECT * FROM History'); - - for(var i = 0; i < rs.rows.length; i++) { - var row = rs.rows.item(i); - row.date = Qt.formatDate(row.time, "yyyy-MM-dd"); - row.originalIndex = historyModel.count; - historyModel.append(row); - } - } - ) - } -//END DATABASE - //BEGIN MODELS - ListModel { + CallHistoryModel { id: historyModel } //END MODELS //BEGIN UI PlasmaExtras.ConditionalLoader { anchors.fill: parent property bool shouldShow: root.visible && (dialerUtils.callState == "idle" || dialerUtils.callState == "failed") when: shouldShow source: Qt.resolvedUrl("Dialer/DialPage.qml") z: shouldShow ? 2 : 0 opacity: shouldShow ? 1 : 0 Behavior on opacity { OpacityAnimator { duration: Kirigami.Units.shortDuration easing.type: Easing.InOutQuad } } } PlasmaExtras.ConditionalLoader { anchors.fill: parent property bool shouldShow: dialerUtils.callState != "idle" && dialerUtils.callState != "failed" when: shouldShow source: Qt.resolvedUrl("Call/CallPage.qml") opacity: shouldShow ? 1 : 0 z: shouldShow ? 2 : 0 Behavior on opacity { OpacityAnimator { duration: Kirigami.Units.shortDuration easing.type: Easing.InOutQuad } } } //END UI }