diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e402ec3c..e89a23b9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,334 +1,333 @@ IF(POLICY CMP0017) CMAKE_POLICY(SET CMP0017 NEW) ENDIF(POLICY CMP0017) IF(POLICY CMP0022) CMAKE_POLICY(SET CMP0022 NEW) ENDIF(POLICY CMP0022) IF(POLICY CMP0063) CMAKE_POLICY(SET CMP0063 NEW) ENDIF(POLICY CMP0063) SET(QT_MIN_VERSION "5.2.0") ADD_DEFINITIONS( ${KF5_DEFINITIONS} ${QT_DEFINITIONS} -fexceptions -Wno-error -Wno-reorder -Wno-error=deprecated-declarations ) # It doesn't work in sandboxes IF (NOT ENABLE_SINGLE_INSTANCE) ADD_DEFINITIONS(-DDISABLE_KDBUS_SERVICE=1) ENDIF() # Enable some useful warnings ADD_DEFINITIONS( -Wall -Wextra -Wmissing-declarations -Wmissing-noreturn -Wpointer-arith -Wcast-align -Wwrite-strings -Wformat-nonliteral -Wformat-security -Wswitch-enum -Winit-self -Wmissing-include-dirs -Wundef -Wmissing-format-attribute -Wno-reorder -Wunused -Wuninitialized -Woverloaded-virtual -Wunused-value -pedantic -Wnonnull -Wsequence-point #-Wsystem-headers -Wsizeof-pointer-memaccess #-Wuseless-cast -Wvarargs ) #Add more warnings for compilers that support it. I used this command: #curl https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/Warning-Options.html | \ #grep -E "^[\t ]+
-W[a-zA-Z=-]*" -o | grep -E "\-W[a-zA-Z=-]*" -o > #cat /tmp/48 /tmp/49 | sort | uniq -u # IF (CMAKE_COMPILER_IS_GNUCC) IF (CMAKE_COMPILER_IS_GNUCC) IF (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 4.9) ADD_DEFINITIONS( -Wunused-but-set-parameter -Wconditionally-supported -Wno-cpp # -Wdouble-promotion -Wdate-time -Wdelete-incomplete # -Wfloat-conversion ) ENDIF() IF (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 4.9) ADD_DEFINITIONS( -Wno-pragmas ) ENDIF() IF (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 5.0) ADD_DEFINITIONS( -Wsuggest-override -Wsuggest-final-types -Wsuggest-final-methods -Wbool-compare -Wformat-signedness -Wlogical-not-parentheses -Wnormalized -Wshift-count-negative -Wshift-count-overflow -Wsized-deallocation -Wsizeof-array-argument ) ENDIF() IF (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 6.0) ADD_DEFINITIONS( -Wnull-dereference -Wtautological-compare -Wduplicated-cond -Wmisleading-indentation ) ENDIF() IF (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 7.0) ADD_DEFINITIONS( -Wimplicit-fallthrough -Wduplicated-branches -Wswitch-unreachable -Wformat-overflow -Wformat-truncation -Wnonnull ) ENDIF() IF (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8.0) ADD_DEFINITIONS( -Wmultistatement-macros -Wstringop-truncation -Wif-not-aligned -Wmissing-attributes ) ENDIF() ENDIF() IF (CMAKE_COMPILER_IS_GNUCC) EXECUTE_PROCESS(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE CMAKE_CXX_COMPILER_VERSION) IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6.9 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 4.6) #GCC 4.6 version of those warnings does detect valid C++0x/C++11 as invalid. ADD_DEFINITIONS( -Wno-error=pragmas -Wno-pragmas -Wno-error ) ENDIF() IF (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.7 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 4.7) ADD_DEFINITIONS( -Wmaybe-uninitialized -Wunused-local-typedefs -pedantic ) ENDIF() IF (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.8 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 4.8) # ADD_DEFINITIONS("-Wzero-as-null-pointer-constant") # ADD_DEFINITIONS( -DENABLE_IGNORE_NULL=true ) ENDIF() ELSE() ADD_DEFINITIONS(-Wno-unknown-pragmas -Wno-unknown-warning-option) ENDIF() ADD_DEFINITIONS("-std=c++0x") #Make sure it can access DBUS autogenerated files INCLUDE_DIRECTORIES(SYSTEM ${KF5_INCLUDES} ${Qt5Widgets_INCLUDES} ${Qt5PrintSupport_INCLUDES} ${Qt5Core_INCLUDES} ${CMAKE_BINARY_DIR} ${ringqt_INCLUDE_DIR} ${LIB_TIP_INCLUDE} ${LIB_CONFIG_INCLUDE} ${LIB_CONFIG_WIDGETS} ) # Shared C++ QML components ADD_SUBDIRECTORY( qmlwidgets ) #Build KDE specific files ADD_SUBDIRECTORY( jamikdeintegration ) # Build the QML based first run Wizard ADD_SUBDIRECTORY( wizard ) # Build the QML based interactive video canvas ADD_SUBDIRECTORY( callview ) # Build the advanced phone dialer ADD_SUBDIRECTORY( dialview ) # Build the views and widgets related to the social timeline feature ADD_SUBDIRECTORY( timeline ) # Build the contact and profile photo editor dialog ADD_SUBDIRECTORY( photoselector ) # Build the elements used to notify the users of events ADD_SUBDIRECTORY( canvasindicators ) # Build the contact manager subsystem ADD_SUBDIRECTORY( contactview ) # Build the account manager subsystem ADD_SUBDIRECTORY( accountview ) # Build the main desktop component ADD_SUBDIRECTORY( desktopview ) # ADD_DEPENDENCIES(desktopview DEPENDS jamikdeintegration) IF(${CMAKE_BUILD_TYPE} MATCHES Release) MESSAGE("NO DEBUG OUTPUT") ADD_DEFINITIONS( -DQT_NO_DEBUG_OUTPUT) ELSE() ENDIF(${CMAKE_BUILD_TYPE} MATCHES Release) SET( ring_kde_SRCS main.cpp cmd.cpp ringapplication.cpp - errormessage.cpp ) # generate rules for building source files from the resources SET(QtApp_RCCS qrc/resources.qrc # conf/confresources.qrc ../data/appicon.qrc ) QT5_ADD_RESOURCES(QtApp_RCC_SRCS ${QtApp_RCCS}) # add_subdirectory( test ) #Enable again some day, it cause compile problems for some users IF(NOT (${ENABLE_VIDEO} MATCHES false)) SET(ENABLE_VIDEO 1 CACHE BOOLEAN "Enable video") ADD_DEFINITIONS( -DENABLE_VIDEO=true ) SET ( config_ui_files ${config_ui_files} conf/dlgvideobase.ui ) ENDIF(NOT (${ENABLE_VIDEO} MATCHES false)) IF(${DISABLE_UNIQUE_APPLICATION} MATCHES true) MESSAGE("KUniqueApplication disabled") SET(DISABLE_UNIQUE_APPLICATION 1 CACHE BOOLEAN "Disable KUniqueApplication") ADD_DEFINITIONS( -DDISABLE_UNIQUE_APPLICATION=true ) ENDIF(${DISABLE_UNIQUE_APPLICATION} MATCHES true) ki18n_wrap_ui(ring_kde_SRCS ${config_ui_files} ) IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") ADD_EXECUTABLE(ring-kde MACOSX_BUNDLE ${ring_kde_SRCS} ${QtApp_RCC_SRCS}) set_source_files_properties( ../data/ring-kdeui.rc PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) file( COPY ../data/ring-kdeui.rc DESTINATION "ring-kde.app/Contents/Resources/" ) ELSE() ADD_EXECUTABLE(ring-kde ${ring_kde_SRCS} ${QtApp_RCC_SRCS}) ENDIF() IF(NOT ${ENABLE_STATIC} MATCHES false) FIND_PACKAGE(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED DBus) INCLUDE_DIRECTORIES(SYSTEM ${Qt5DBus_INCLUDE_DIRS} ) LINK_DIRECTORIES(${Qt5DBus_LIBRARY_DIRS} ) ADD_DEFINITIONS(${Qt5DBus_CFLAGS}) IF(NOT DEFINED OS_ANDROID) TARGET_LINK_LIBRARIES(ring-kde -lpthread ) ENDIF() TARGET_LINK_LIBRARIES(ring-kde ${ringqt_LIBRARY_STATIC} ) IF(NOT ${ENABLE_LIBWRAP}) TARGET_LINK_LIBRARIES(ring-kde ${Qt5DBus_LIBRARIES} ) ENDIF() ELSE() TARGET_LINK_LIBRARIES(ring-kde ${ringqt_LIBRARY_DYNAMIC}) ENDIF() QT5_ADD_DBUS_ADAPTOR(ring_kde_SRCS ../data/org.kde.kuiserver.xml cmd.h Cmd ) TARGET_LINK_LIBRARIES(ring-kde jamiwizard jamicallview jamidialview jamitimelineview - libphotoselector + jamiphotoselector jamicanvasindicator desktopview jamicontactview jamiaccountview libqmlwidgets kquickitemviews jamikdeintegration # RingQt ringqtquick # Qt5 Qt5::Widgets Qt5::Core Qt5::Gui Qt5::Svg Qt5::PrintSupport # KF5 KF5::I18n KF5::WidgetsAddons KF5::ConfigCore KF5::ConfigGui KF5::DBusAddons KF5::XmlGui KF5::Notifications KF5::IconThemes KF5::Crash KF5::NotifyConfig KF5::GlobalAccel KF5::Declarative KF5::Kirigami2 ) IF (Qt5TextToSpeech_FOUND) TARGET_LINK_LIBRARIES(ring-kde Qt5::TextToSpeech ) ENDIF() ########### install files ############### INSTALL( TARGETS ring-kde DESTINATION ${BIN_INSTALL_DIR} ) INSTALL( FILES wizard/assets/beta_logo.svg DESTINATION ${DATA_INSTALL_DIR}/ring-kde ) diff --git a/src/cmd.cpp b/src/cmd.cpp index d430ffcf..1b220a5c 100644 --- a/src/cmd.cpp +++ b/src/cmd.cpp @@ -1,221 +1,219 @@ /*************************************************************************** * Copyright (C) 2013-2015 by Savoir-Faire Linux * * Author : Emmanuel Lepage Vallee * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, 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 General Public License * * along with this program. If not, see . * **************************************************************************/ #include "cmd.h" //Qt #include #include #include #include //KDE #include #include //Ring #include #include #include #include #include "ringapplication.h" #include "kcfg_settings.h" //Static definition Cmd* Cmd::m_spSelf = nullptr; ///(Private) constructor Cmd::Cmd(QObject* parent) : QObject(parent) { } ///Signleton Cmd* Cmd::instance() { if (!m_spSelf) { m_spSelf = new Cmd(); } return m_spSelf; } ///Setup command line options before passing them to the KUniqueApplication bool Cmd::parseCmd(int argc, char **argv, KAboutData& about) { Q_UNUSED(argc) Q_UNUSED(argv) QCoreApplication* app = QCoreApplication::instance(); QCommandLineOption call (QStringList { "place-call" }, i18n("Place a call to a given number" ), QStringLiteral("number" ), QLatin1String("")); QCommandLineOption text (QStringList { "send-text" }, i18n("Send a text to <number>, use --message to set the content, then hangup"), QStringLiteral("number" ), QLatin1String("")); QCommandLineOption message (QStringList { "message" }, i18n("Used in combination with --send-text" ), QStringLiteral("content"), QLatin1String("")); QCommandLineOption icon (QStringList { "iconify" }, i18n("Start in the system tray" ) ); QCommandLineOption showPhone (QStringList { "phone" }, i18n("Start with the phone interface" ) ); QCommandLineOption showTimeL (QStringList { "timeline" }, i18n("Start with the timeline interface" ) ); QCommandLineParser parser; parser.addOptions({call,text,message,icon,showPhone,showTimeL}); about.setupCommandLine(&parser); parser.process(*app); about.processCommandLine(&parser); const auto versionOption = parser.addVersionOption(); const auto helpOption = parser.addHelpOption (); if (parser.isSet(versionOption) || parser.isSet(helpOption)) return false; - RingApplication::instance()->init(); - if (parser.isSet(call)) placeCall(parser.value(call)); if (parser.isSet(icon)) iconify(); if (parser.isSet(showPhone)) phoneInterface(); if (parser.isSet(showTimeL)) timelineInterface(); if (parser.isSet(text) && parser.isSet(message)) sendText(parser.value(text),parser.value(message)); return true; } ///Place a call (from the command line) void Cmd::placeCall(const QString& number) { if (number.isEmpty()) { qWarning() << "Example: --place-call 123@example.com"; return; } //Wait until the initialization is done QTimer::singleShot(0,[number] { Call* call = Session::instance()->callModel()->dialingCall(); call->reset(); call->appendText(number); call->performAction(Call::Action::ACCEPT); }); } ///Send a text ans hang up (from the command line) void Cmd::sendText(const QString& number, const QString& text) { Q_UNUSED(number) Q_UNUSED(text) QTimer::singleShot(0,[number,text] { Call* call = Session::instance()->callModel()->dialingCall(); call->reset(); call->appendText(number); call->setProperty("message",text); QObject::connect(call,&Call::lifeCycleStateChanged,[text,call](const Call::LifeCycleState st) { if (st == Call::LifeCycleState::PROGRESS) { call->addOutgoingMedia()->send({{"text/plain",call->property("message").toString()}}); call->performAction(Call::Action::REFUSE); //HangUp } }); call->performAction(Call::Action::ACCEPT); }); } void Cmd::iconify() { if (RingApplication::instance()) { RingApplication::instance()->setIconify(true); } } void Cmd::phoneInterface() { //FIXME } void Cmd::timelineInterface() { //FIXME } void Cmd::slotActivateActionRequested (const QString&, const QVariant&) { } /** * This function is called when a new client try to open. It will stop but this * process need to take care of its arguments. */ void Cmd::slotActivateRequested (const QStringList& args, const QString& cwd) { Q_UNUSED(cwd) enum class Current { NONE , /* No args */ PLACE_CALL, /* One arg */ SEND_TEXT , /* One arg */ MESSAGE , /* One arg */ MINIMIZED /* No args */ }; Current current = Current::NONE; bool sendMessage = false; QStringList messages; QString sendTextTo; for(const QString& arg : args) { if (current != Current::NONE) { switch(current) { case Current::NONE : case Current::MINIMIZED : //Iconify do nothing when the executable is already started break; case Current::SEND_TEXT : sendTextTo = arg; break; case Current::PLACE_CALL: placeCall(arg); break; case Current::MESSAGE : messages << arg; break; } } else { if (arg == QLatin1String("--place-call")) current = Current::PLACE_CALL; else if (arg == QLatin1String("--send-text")) sendMessage = true; else if (arg == QLatin1String("--message")) current = Current::MESSAGE; else if (arg == QLatin1String("--iconify")) {}//TODO } } if (sendMessage && sendTextTo.size() && messages.size()) { foreach (const QString& msg, messages) sendText(sendTextTo, msg); } } void Cmd::slotOpenRequested (const QList&) { } // kate: space-indent on; indent-width 3; replace-tabs on; diff --git a/src/errormessage.cpp b/src/errormessage.cpp deleted file mode 100644 index 2551b6d4..00000000 --- a/src/errormessage.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013-2015 by Savoir-Faire Linux * - * Author : Emmanuel Lepage Vallee * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 3 of the License, 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 General Public License * - * along with this program. If not, see . * - **************************************************************************/ -#include "errormessage.h" -#include - -///Error to display when there is nothing else to say -const QString ErrorMessage::GENERIC_ERROR = i18n("An unknown error occurred. Ring KDE will now exit. If the problem persist, please report a bug.\n\n" - "It is known that this message can be caused by trying to open Ring KDE while the Ring daemon is exiting. If so, waiting 15 seconds and " - "trying again will solve the issue."); - -///When the daemon is not detected -const QString ErrorMessage::NO_DAEMON_ERROR = i18n("The Ring daemon (dring) is not available. Please be sure it is installed correctly or launch it manually. \n\n\ -Check in your distribution repository if the Ring daemon (sometime called \"ring-daemon\") is available.\n\ -Help for building Ring daemon from source are present at https://projects.savoirfairelinux.com/projects/sflphone/wiki/How_to_build"); - -// kate: space-indent on; indent-width 3; replace-tabs on; diff --git a/src/errormessage.h b/src/errormessage.h deleted file mode 100644 index e918a225..00000000 --- a/src/errormessage.h +++ /dev/null @@ -1,32 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013-2015 by Savoir-Faire Linux * - * Author : Emmanuel Lepage Vallee * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 3 of the License, 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 General Public License * - * along with this program. If not, see . * - **************************************************************************/ - -#ifndef ERROR_MESSAGES_H -#define ERROR_MESSAGES_H - -#include - -class ErrorMessage { -public: - static const QString GENERIC_ERROR; - static const QString NO_DAEMON_ERROR; -}; - -#endif - -// kate: space-indent on; indent-width 3; replace-tabs on; diff --git a/src/main.cpp b/src/main.cpp index 528b228f..942f3781 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,246 +1,261 @@ /*************************************************************************** * Copyright (C) 2009-2015 by Savoir-Faire Linux * * Author : Jérémy Quentin * * Emmanuel Lepage Vallee * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, 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 General Public License * * along with this program. If not, see . * **************************************************************************/ //Qt #include #include #include #include //KDE #include #include #include //Ring #include "ringapplication.h" #include "kcfg_settings.h" #include "cmd.h" #include #include #ifdef KQUICKITEMVIEWS_USE_STATIC_PLUGIN Q_IMPORT_PLUGIN(KQuickItemViews) #else #include #endif #ifdef JAMIKDEINTEGRATION_USE_STATIC_PLUGIN Q_IMPORT_PLUGIN(JamiKDEIntegration) #else #include #endif #ifdef JAMIWIZARD_USE_STATIC_PLUGIN Q_IMPORT_PLUGIN(JamiWizard) #else #include #endif #ifdef JAMIACCOUNTVIEW_USE_STATIC_PLUGIN Q_IMPORT_PLUGIN(JamiAccountView) #else #include #endif #ifdef JAMIACCOUNTVIEW_USE_STATIC_PLUGIN Q_IMPORT_PLUGIN(JamiCallView) #else #include #endif #ifdef JAMIACCOUNTVIEW_USE_STATIC_PLUGIN Q_IMPORT_PLUGIN(JamiContactView) #else #include #endif #ifdef JAMIACCOUNTVIEW_USE_STATIC_PLUGIN Q_IMPORT_PLUGIN(JamiDialView) #else #include #endif #ifdef JAMIACCOUNTVIEW_USE_STATIC_PLUGIN Q_IMPORT_PLUGIN(JamiTimelineView) #else #include #endif #ifdef JAMICANVASINDICATOR_USE_STATIC_PLUGIN Q_IMPORT_PLUGIN(JamiCanvasIndicator) #else #include #endif +#ifdef JAMIPHOTOSELECTOR_USE_STATIC_PLUGIN +Q_IMPORT_PLUGIN(JamiPhotoSelector) +#else +#include +#endif + Q_IMPORT_PLUGIN(RingQtQuick) constexpr static const char version[] = "3.1.0"; int main(int argc, char **argv) { try { //QQmlDebuggingEnabler enabler; QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); RingApplication app( argc, argv ); KLocalizedString::setApplicationDomain("ring-kde"); //FIXME remove #ifdef KQUICKITEMVIEWS_USE_STATIC_PLUGIN qobject_cast(qt_static_plugin_KQuickItemViews().instance())->registerTypes("org.kde.playground.kquickitemviews"); #else KQuickItemViews v; v.registerTypes("org.kde.playground.kquickitemviews"); #endif qobject_cast(qt_static_plugin_RingQtQuick().instance())->registerTypes("net.lvindustries.ringqtquick"); qobject_cast(qt_static_plugin_RingQtQuick().instance())->initializeEngine(app.engine(), "net.lvindustries.ringqtquick"); #ifdef JAMIKDEINTEGRATION_USE_STATIC_PLUGIN qobject_cast(qt_static_plugin_JamiKDEIntegration().instance())->registerTypes("org.kde.ringkde.jamikdeintegration"); qobject_cast(qt_static_plugin_JamiKDEIntegration().instance())->initializeEngine(app.engine(), "org.kde.ringkde.jamikdeintegration"); #else JamiKDEIntegration v2; v2.registerTypes("org.kde.ringkde.jamikdeintegration"); v2.initializeEngine(app.engine(), "org.kde.ringkde.jamikdeintegration"); #endif #ifdef JAMIWIZARD_USE_STATIC_PLUGIN qobject_cast(qt_static_plugin_JamiWizard().instance())->registerTypes("org.kde.ringkde.jamiwizard"); qobject_cast(qt_static_plugin_JamiWizard().instance())->initializeEngine(app.engine(), "org.kde.ringkde.jamiwizard"); #else JamiWizard v3; v3.registerTypes("org.kde.ringkde.jamiwizard"); v3.initializeEngine(app.engine(), "org.kde.ringkde.jamiwizard"); #endif #ifdef JAMIACCOUNTVIEW_USE_STATIC_PLUGIN qobject_cast(qt_static_plugin_JamiAccountView().instance())->registerTypes("org.kde.ringkde.jamiaccountview"); qobject_cast(qt_static_plugin_JamiAccountView().instance())->initializeEngine(app.engine(), "org.kde.ringkde.jamiaccountview"); #else JamiAccountView v4; v4.registerTypes("org.kde.ringkde.jamiaccountview"); v4.initializeEngine(app.engine(), "org.kde.ringkde.jamiaccountview"); #endif #ifdef JAMIACCOUNTVIEW_USE_STATIC_PLUGIN qobject_cast(qt_static_plugin_JamiCallView().instance())->registerTypes("org.kde.ringkde.jamicallview"); qobject_cast(qt_static_plugin_JamiCallView().instance())->initializeEngine(app.engine(), "org.kde.ringkde.jamicallview"); #else JamiCallViewPlugin v5; v5.registerTypes("org.kde.ringkde.jamicallview"); v5.initializeEngine(app.engine(), "org.kde.ringkde.jamicallview"); #endif #ifdef JAMICONTACTVIEW_USE_STATIC_PLUGIN qobject_cast(qt_static_plugin_JamiContactView().instance())->registerTypes("org.kde.ringkde.jamicontactview"); qobject_cast(qt_static_plugin_JamiContactView().instance())->initializeEngine(app.engine(), "org.kde.ringkde.jamicontactview"); #else JamiContactViewPlugin v6; v6.registerTypes("org.kde.ringkde.jamicontactview"); v6.initializeEngine(app.engine(), "org.kde.ringkde.jamicontactview"); #endif #ifdef JAMIDIALVIEW_USE_STATIC_PLUGIN qobject_cast(qt_static_plugin_JamiDialView().instance())->registerTypes("org.kde.ringkde.jamidialview"); qobject_cast(qt_static_plugin_JamiDialView().instance())->initializeEngine(app.engine(), "org.kde.ringkde.jamidialview"); #else JamiDialView v7; v7.registerTypes("org.kde.ringkde.jamidialview"); v7.initializeEngine(app.engine(), "org.kde.ringkde.jamidialview"); #endif #ifdef JAMITIMELINEVIEW_USE_STATIC_PLUGIN qobject_cast(qt_static_plugin_JamiTimelineView().instance())->registerTypes("org.kde.ringkde.jamitimelineview"); qobject_cast(qt_static_plugin_JamiTimelineView().instance())->initializeEngine(app.engine(), "org.kde.ringkde.jamitimelineview"); #else JamiTimelineView v8; v8.registerTypes("org.kde.ringkde.jamitimelineview"); v8.initializeEngine(app.engine(), "org.kde.ringkde.jamitimelineview"); #endif #ifdef JAMICANVASINDICATOR_USE_STATIC_PLUGIN qobject_cast(qt_static_plugin_JamiCanvasIndicator().instance())->registerTypes("org.kde.ringkde.jamicanvasindicator"); qobject_cast(qt_static_plugin_JamiCanvasIndicator().instance())->initializeEngine(app.engine(), "org.kde.ringkde.jamicanvasindicator"); #else JamiCanvasIndicator v9; v9.registerTypes("org.kde.ringkde.jamicanvasindicator"); v9.initializeEngine(app.engine(), "org.kde.ringkde.jamicanvasindicator"); #endif +#ifdef JAMIPHOTOSELECTOR_USE_STATIC_PLUGIN + qobject_cast(qt_static_plugin_JamiPhotoSelector().instance())->registerTypes("org.kde.ringkde.jamiphotoselector"); + qobject_cast(qt_static_plugin_JamiPhotoSelector().instance())->initializeEngine(app.engine(), "org.kde.ringkde.jamiphotoselector"); +#else + JamiPhotoSelector v10; + v10.registerTypes("org.kde.ringkde.jamiphotoselector"); + v10.initializeEngine(app.engine(), "org.kde.ringkde.jamiphotoselector"); +#endif + KAboutData about(QStringLiteral("ring-kde"), i18n("ring-kde"), /*QStringLiteral(*/version/*)*/, i18n("RING, a secured and distributed communication software"), KAboutLicense::GPL_V3, i18n("(C) 2004-2015 Savoir-faire Linux\n2016-2017 Emmanuel Lepage Vallee"), QString(), QStringLiteral("http://www.ring.cx"), QStringLiteral("ring@gnu.org") ); about.setOrganizationDomain(QByteArray("kde.org")); about.setProgramLogo(QImage(QStringLiteral(":appicon/icons/64-apps-ring-kde.png"))); about.addAuthor( i18n( "Emmanuel Lepage-Vallée" ), QString(), QStringLiteral("elv1313@gmail.com" )); about.addAuthor( i18n( "Alexandre Lision" ), QString(), QStringLiteral("alexandre.lision@savoirfairelinux.com")); about.addCredit( i18n( "Based on the SFLphone teamworks" ), QString(), QString() ); if (!Cmd::parseCmd(argc, argv, about)) return 0; KAboutData::setApplicationData(about); app.setOrganizationDomain(QStringLiteral("ring.cx")); //Only start the application once #ifdef Q_OS_LINUX #ifndef DISABLE_KDBUS_SERVICE KDBusService service(KDBusService::Unique); QObject::connect(&service, &KDBusService::activateActionRequested, Cmd::instance(), &Cmd::slotActivateActionRequested); QObject::connect(&service, &KDBusService::activateRequested , Cmd::instance(), &Cmd::slotActivateRequested ); QObject::connect(&service, &KDBusService::openRequested , Cmd::instance(), &Cmd::slotOpenRequested ); #endif #endif //The app will have quitted by now if an instance already exist app.newInstance(); const int retVal = app.exec(); ConfigurationSkeleton::self()->save(); return retVal; } catch(const char * msg) { qDebug() << msg; } catch(QString& msg) { qDebug() << msg; } } // kate: space-indent on; indent-width 3; replace-tabs on; diff --git a/src/photoselector/CMakeLists.txt b/src/photoselector/CMakeLists.txt index bbb13bd4..cf75a584 100644 --- a/src/photoselector/CMakeLists.txt +++ b/src/photoselector/CMakeLists.txt @@ -1,67 +1,123 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.4) +cmake_minimum_required(VERSION 3.0) -ADD_DEFINITIONS("-std=c++11") +project(jamiphotoselector) -PROJECT(libphotoselector) +if(POLICY CMP0063) + CMAKE_POLICY(SET CMP0063 NEW) +endif(POLICY CMP0063) -FIND_PACKAGE(ECM 1.1.0 REQUIRED NO_MODULE) +find_package(ECM 1.1.0 REQUIRED NO_MODULE) +list(APPEND CMAKE_MODULE_PATH "${ECM_MODULE_PATH}") -INCLUDE(ECMInstallIcons) -INCLUDE(ECMOptionalAddSubdirectory) +include(ECMInstallIcons) +include(ECMOptionalAddSubdirectory) +include(CMakePackageConfigHelpers) -INCLUDE(KDEInstallDirs) -INCLUDE(KDECMakeSettings) -INCLUDE(KDECompilerSettings) +include(KDEInstallDirs) +include(KDECMakeSettings) +include(KDECompilerSettings) -SET(CMAKE_AUTOMOC ON) -SET(CMAKE_AUTORCC ON) -SET(CMAKE_AUTOUIC ON) +SET(CMAKE_C_VISIBILITY_PRESET hidden) +SET(CMAKE_CXX_VISIBILITY_PRESET hidden) +SET(CMAKE_VISIBILITY_INLINES_HIDDEN 1) -FIND_PACKAGE ( LibRingQt QUIET ) +# When used with `add_subdirectory`, assume it is a static Qt plugin +get_directory_property(USES_ADD_SUBDIRECTORY PARENT_DIRECTORY) +if(USES_ADD_SUBDIRECTORY) + set(BUILD_SHARED_LIBS OFF) +endif() -FIND_PACKAGE(Qt5 CONFIG REQUIRED - Core - Gui - Widgets - Quick - QuickWidgets - QuickControls2 -) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) -FIND_PACKAGE(KF5 REQUIRED COMPONENTS - I18n - Config - ConfigWidgets -) +set(CMAKE_CXX_STANDARD 14) -INCLUDE_DIRECTORIES(SYSTEM ${Qt5Widgets_INCLUDES} ${Qt5Core_INCLUDES} ${ringqt_INCLUDE_DIR}) +if(NOT BUILD_SHARED_LIBS) + set(ENABLE_STATIC_PLUGIN 1) # Used in Config.cmake.in + add_definitions(-DQT_PLUGIN) + add_definitions(-DQT_STATICPLUGIN=1) + add_definitions(-DJAMIPHOTOSELECTOR_USE_STATIC_PLUGIN=1) +endif() -ADD_DEFINITIONS(${Qt5Core_DEFINITIONS}) +find_package(Qt5 CONFIG REQUIRED + Core Gui Quick QuickControls2 +) -SET(GENERIC_LIB_VERSION "1.0.0") +set(GENERIC_LIB_VERSION "1.0.0") #File to compile -SET( libphotoselector_LIB_SRCS +set( jamiphotoselector_LIB_SRCS photoselector.cpp photoplugin.cpp ) -QT5_ADD_RESOURCES(libphotoselector_LIB_SRCS +qt5_add_resources(jamiphotoselector_LIB_SRCS photoselector.qrc ) -ADD_LIBRARY( libphotoselector STATIC ${libphotoselector_LIB_SRCS} ) +set(AUTOMOC_MOC_OPTIONS -Muri=org.kde.ringkde.jamiphotoselector) -target_link_libraries( libphotoselector - ringqt +add_library(jamiphotoselector ${jamiphotoselector_LIB_SRCS} ) - # KF5 - KF5::I18n +target_link_libraries( jamiphotoselector + # Project + ringqt + ringqtquick - # Qt5 + # Qt Qt5::Core Qt5::Gui Qt5::Quick - Qt5::Widgets Qt5::QuickControls2 + + # KF5 + KF5::I18n +) + +# Configure the target config +set(jamiphotoselector_CONFIG_PATH "${CMAKE_CURRENT_BINARY_DIR}/JamiPhotoSelectorConfig.cmake") + +if(USES_ADD_SUBDIRECTORY) + set(JamiPhotoSelector_DIR ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE) +endif() + +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/JamiPhotoSelectorConfig.cmake.in" ${jamiphotoselector_CONFIG_PATH} + INSTALL_DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake/JamiPhotoSelector/ + PATH_VARS INCLUDE_INSTALL_DIR +) + +install( FILES ${jamiphotoselector_CONFIG_PATH} + DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake/JamiPhotoSelector/ + COMPONENT Devel +) + +# Create the target +target_include_directories(jamiphotoselector + PUBLIC + $ + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/ +) + +set_target_properties(jamiphotoselector PROPERTIES + PUBLIC_HEADER + "${jamiphotoselector_EXPORT_HDRS}" +) + +export(TARGETS jamiphotoselector + FILE "${PROJECT_BINARY_DIR}/cmake/JamiPhotoSelectorTargets.cmake" +) + +install(TARGETS jamiphotoselector + EXPORT JamiPhotoSelectorTargets + LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" COMPONENT jamiphotoselector + ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin + COMPONENT Devel +) + +install(EXPORT JamiPhotoSelectorTargets + DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake/JamiPhotoSelector + COMPONENT Devel ) diff --git a/src/photoselector/cmake/JamiPhotoSelectorConfig.cmake.in b/src/photoselector/cmake/JamiPhotoSelectorConfig.cmake.in new file mode 100644 index 00000000..1796e01c --- /dev/null +++ b/src/photoselector/cmake/JamiPhotoSelectorConfig.cmake.in @@ -0,0 +1,8 @@ +@PACKAGE_INIT@ + +#Allow users to when to use Q_IMPORT_PLUGIN in main.cpp +if(@ENABLE_STATIC_PLUGIN@ MATCHES 1) + add_definitions(-DJAMIPHOTOSELECTOR_USE_STATIC_PLUGIN=1) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/JamiPhotoSelectorTargets.cmake") diff --git a/src/photoselector/photoplugin.cpp b/src/photoselector/photoplugin.cpp index b90ef1cb..f801a261 100644 --- a/src/photoselector/photoplugin.cpp +++ b/src/photoselector/photoplugin.cpp @@ -1,36 +1,42 @@ -/*************************************************************************** - * Copyright (C) 2017 by Bluesystems * - * Author : Emmanuel Lepage Vallee * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 3 of the License, 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 General Public License * - * along with this program. If not, see . * - **************************************************************************/ +/************************************************************************************ + * Copyright (C) 2018 by BlueSystems GmbH * + * Author : Emmanuel Lepage Vallee * + * * + * 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 library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***********************************************************************************/ #include "photoplugin.h" -#include +// Qt #include +#include +#include -#include "photoselector.h" - +// QRC #include -PhotoSelectorPlugin::PhotoSelectorPlugin(QObject* parent) : QObject(parent) -{ -} +#include "photoselector.h" -void PhotoSelectorPlugin::registerTypes(const char *uri) +void JamiPhotoSelector::registerTypes(const char *uri) { - Q_ASSERT(uri == QLatin1String("PhotoSelectorPlugin")); + Q_ASSERT(uri == QByteArray("org.kde.ringkde.jamiphotoselector")); qmlRegisterType(uri, 1, 0, "PhotoSelector"); } + +void JamiPhotoSelector::initializeEngine(QQmlEngine *engine, const char *uri) +{ + Q_UNUSED(engine) + Q_UNUSED(uri) +} diff --git a/src/photoselector/photoplugin.h b/src/photoselector/photoplugin.h index b7c1f244..b9b856de 100644 --- a/src/photoselector/photoplugin.h +++ b/src/photoselector/photoplugin.h @@ -1,33 +1,31 @@ -/*************************************************************************** - * Copyright (C) 2017 by Bluesystems * - * Author : Emmanuel Lepage Vallee * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 3 of the License, 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 General Public License * - * along with this program. If not, see . * - **************************************************************************/ +/************************************************************************************ + * Copyright (C) 2019 by BlueSystems GmbH * + * Author : Emmanuel Lepage Vallee * + * * + * 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 library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***********************************************************************************/ #pragma once #include -//![plugin] -class Q_DECL_EXPORT PhotoSelectorPlugin final : public QObject//QQmlExtensionPlugin +class Q_DECL_EXPORT JamiPhotoSelector final : public QQmlExtensionPlugin { Q_OBJECT -// Q_PLUGIN_METADATA(IID "PhotoSelectorPlugin") -public: - explicit PhotoSelectorPlugin(QObject* parent = nullptr); + Q_PLUGIN_METADATA(IID "org.kde.ringkde.jamiphotoselector" FILE "photoselector.json") public: - void registerTypes(const char *uri);// override; + void registerTypes(const char* uri) override; + virtual void initializeEngine(QQmlEngine* engine, const char* uri) override; }; -//![plugin] diff --git a/src/photoselector/photoselector.json b/src/photoselector/photoselector.json new file mode 100644 index 00000000..da628197 --- /dev/null +++ b/src/photoselector/photoselector.json @@ -0,0 +1,4 @@ +{ + "Keys": [ "org.kde.ringkde.jamiphotoselector" ], + "uri": ["org.kde.ringkde.jamiphotoselector"] +} diff --git a/src/qmlwidgets/qml/outlinebutton.qml b/src/qmlwidgets/qml/outlinebutton.qml index 041c988c..2710a815 100644 --- a/src/qmlwidgets/qml/outlinebutton.qml +++ b/src/qmlwidgets/qml/outlinebutton.qml @@ -1,207 +1,202 @@ /*************************************************************************** * Copyright (C) 2017-2018 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, 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 General Public License * * along with this program. If not, see . * **************************************************************************/ import QtQuick 2.0 import Ring 1.0 import org.kde.kirigami 2.2 as Kirigami -// import RingQmlWidgets 1.0 -import org.kde.ringkde.jamicontactview 1.0 as JamiContactView - import RingQmlWidgets 1.0 -import PhotoSelectorPlugin 1.0 - Item { id: button property color color: activePalette.text property string label: "" property real expandedHeight: height property real radius: Math.min(48, button.height) / 2 property real topPadding: (button.height - (radius*2)) / 2 property real sideMargin: 10 property var alignment: Qt.AlignHCenter property alias icon: icn.source implicitWidth: height width: implicitWidth signal clicked() Rectangle { id: addCallButton clip: true /** * Handle both when there is a single button + alignment and when it is * part of a group. */ anchors.horizontalCenter: button.alignment == Qt.AlignHCenter ? parent.horizontalCenter : undefined anchors.right: button.alignment == Qt.AlignRight ? parent.right : undefined anchors.left: button.alignment == Qt.AlignLeft ? parent.left : undefined visible: false y: button.topPadding height: button.radius*2 width: button.radius*2 radius: button.radius color: "transparent" border.width: 1 border.color: button.color opacity: 0 Rectangle { id: background anchors.fill: parent color: button.color opacity: 0 Behavior on opacity { NumberAnimation {duration: 300; easing.type: Easing.OutQuad } } } Behavior on width { NumberAnimation {duration: 200; easing.type: Easing.OutQuad } } Behavior on height { NumberAnimation {duration: 200; easing.type: Easing.OutQuad } } Behavior on radius { NumberAnimation {duration: 100; easing.type: Easing.OutQuad } } Behavior on opacity { NumberAnimation {duration: 200; easing.type: Easing.OutQuad } } Item { id: icon width: button.radius*2 height: button.radius*2 anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left Rectangle { visible: icn.source == "" width: 1 height: button.radius anchors.centerIn: parent color: button.color } Rectangle { visible: icn.source == "" height: 1 width: button.radius anchors.centerIn: parent color: button.color } Image { id: icn width: 16//Math.sqrt(2*parent.width) // the largest square fitting in a circle height: width sourceSize.width: width sourceSize.height: width anchors.centerIn: parent } } Text { id: label opacity: 0 color: button.color text: button.label font.pointSize: Kirigami.Theme.defaultFont.pointSize*1.6 Behavior on opacity { NumberAnimation {duration: 200; easing.type: Easing.OutQuad } } // Avoid overlapping the icon when the width isn't large enough anchors.centerIn: implicitWidth > (button.width) ? undefined : parent anchors.right: implicitWidth > (button.width) ? addCallButton.right : undefined } MouseArea { id: mouseGrabber anchors.fill: parent hoverEnabled: true onClicked: { button.clicked() } } StateGroup { id: stateGroup states: [ State { name: "hover" when: mouseGrabber.containsMouse extend: "active" PropertyChanges { target: addCallButton opacity: 0.8 radius: 5 height: button.expandedHeight width: addCallButton.parent.width - 2*button.sideMargin } PropertyChanges { target: background opacity: 0.1 } PropertyChanges { target: label opacity: 0.8 } PropertyChanges { target: button height: button.expandedHeight implicitWidth: label.implicitWidth + 2*height + 2 } }, State { name: "active" when: button.visible PropertyChanges { target: addCallButton visible: true opacity: 0.5 radius: 99 width: button.radius*2 } PropertyChanges { target: background opacity: 0 } PropertyChanges { target: label opacity: 0 } PropertyChanges { target: button implicitWidth: height } } ] } } } diff --git a/src/ringapplication.cpp b/src/ringapplication.cpp index f99af683..57462edf 100644 --- a/src/ringapplication.cpp +++ b/src/ringapplication.cpp @@ -1,322 +1,288 @@ /*************************************************************************** * Copyright (C) 2009-2015 by Savoir-Faire Linux * * Author : Emmanuel Lepage Valle * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, 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 General Public License * * along with this program. If not, see . * **************************************************************************/ //Parent #include "ringapplication.h" //Qt #include #include #include #include #include #include #include #include #include #include #include //KDE #include #include #include #include +#include //LRC #include #include #include #include #include #include #include //Ring #include "kcfg_settings.h" #include "cmd.h" -#include "errormessage.h" #include "wizard/welcome.h" #include "jamikdeintegration/src/windowevent.h" //Models #include #include #include #include #include //Delegates #include "extensions/presencecollectionextension.h" //QML #include #include "qmlwidgets/plugin.h" #include "qmlwidgets/symboliccolorizer.h" -#include "photoselector/photoplugin.h" #include "desktopview/desktopviewplugin.h" + +///Error to display when there is nothing else to say +static const QString GENERIC_ERROR = i18n("An unknown error occurred. Ring KDE will now exit. If the problem persist, please report a bug.\n\n" + "It is known that this message can be caused by trying to open Ring KDE while the Ring daemon is exiting. If so, waiting 15 seconds and " + "trying again will solve the issue."); + + KDeclarative::KDeclarative* RingApplication::m_pDeclarative {nullptr}; RingQmlWidgets* RingApplication::m_pQmlWidget {nullptr}; -PhotoSelectorPlugin* RingApplication::m_pPhotoSelector {nullptr}; DesktopView* RingApplication::m_pDesktopView {nullptr}; RingApplication* RingApplication::m_spInstance {nullptr}; //This code detect if the window is active, innactive or minimzed class PhoneWindowEvent final : public QObject { Q_OBJECT public: PhoneWindowEvent(RingApplication* ev) : QObject(ev),m_pParent(ev) { QTimer::singleShot(0, [this]() { m_pParent->desktopWindow()->installEventFilter(this); }); } protected: virtual bool eventFilter(QObject *obj, QEvent *event) override { Q_UNUSED(obj) if (event->type() == QEvent::WindowDeactivate) { m_pParent->m_HasFocus = false; } else if (event->type() == QEvent::WindowActivate) { m_pParent->m_HasFocus = true; } return false; } private: RingApplication* m_pParent; Q_SIGNALS: void minimized(bool); }; /** * The application constructor */ RingApplication::RingApplication(int & argc, char ** argv) : QApplication(argc,argv),m_StartIconified(false) { Q_ASSERT(argc != -1); setAttribute(Qt::AA_EnableHighDpiScaling); m_pEventFilter = new PhoneWindowEvent(this); m_spInstance = this; } -void RingApplication::init() -{ - if ((!Session::instance()->callModel()->isConnected()) || (!Session::instance()->callModel()->isValid())) { - QTimer::singleShot(5000,this,&RingApplication::daemonTimeout); - } -} - /** * Destructor */ RingApplication::~RingApplication() { delete m_pDeclarative; delete engine(); - delete m_pPhotoSelector; delete m_pQmlWidget; m_spInstance = nullptr; } RingApplication* RingApplication::instance() { Q_ASSERT(m_spInstance); return m_spInstance; } ///Parse command line arguments int RingApplication::newInstance() { static bool displayWizard = ConfigurationSkeleton::enableWizard() || ConfigurationSkeleton::showSplash(); const bool displayOnStart = ConfigurationSkeleton::displayOnStart() && !startIconified(); static bool init = true; //Only call on the first instance if (init) { init = false; desktopWindow(); } // The first run wizard if (displayOnStart && displayWizard) { // Also add this object engine()->rootContext()->setContextProperty( QStringLiteral("RingApplication"), this ); if (ConfigurationSkeleton::enableWizard()) WindowEvent::instance()->showWizard(); if (!Session::instance()->accountModel()->size()) WindowEvent::instance()->showWizard(); ConfigurationSkeleton::setEnableWizard(false); displayWizard = false; return 0; } return 0; } bool RingApplication::startIconified() const { return m_StartIconified; } void RingApplication::setIconify(bool iconify) { m_StartIconified = iconify; } #define QML_TYPE(name) qmlRegisterUncreatableType(AppName, 1,0, #name, #name "cannot be instantiated"); #define QML_NS(name) qmlRegisterUncreatableMetaObject( name :: staticMetaObject, #name, 1, 0, #name, "Namespaces cannot be instantiated" ); #define QML_CRTYPE(name) qmlRegisterType(AppName, 1,0, #name); constexpr static const char AppName[]= "Ring"; /// Create a QML engine for various canvas widgets QQmlApplicationEngine* RingApplication::engine() { static QQmlApplicationEngine* e = nullptr; static std::atomic_flag engineInit = ATOMIC_FLAG_INIT; if (!engineInit.test_and_set()) { m_pQmlWidget = new RingQmlWidgets; m_pQmlWidget->registerTypes("RingQmlWidgets"); - m_pPhotoSelector = new PhotoSelectorPlugin; - m_pPhotoSelector->registerTypes("PhotoSelectorPlugin"); - m_pDesktopView = new DesktopView; m_pDesktopView->registerTypes("DesktopView"); QML_TYPE( QAction) QML_CRTYPE( QItemSelectionModel ) QML_NS(Ring) e = new QQmlApplicationEngine(QGuiApplication::instance()); // Setup the icon theme provider and ki18n m_pDeclarative = new KDeclarative::KDeclarative; m_pDeclarative->setDeclarativeEngine(e); try { auto im2 = new SymbolicColorizer(); e->addImageProvider( QStringLiteral("SymbolicColorizer"), im2 ); } catch(char const* e) { qDebug() << "Failed to connect to the daemon" << e; sync(); ::exit(1); } catch(...) { qDebug() << "Failed to connect to the daemon with an unknown problem"; ::exit(2); } } return e; } #undef QML_TYPE #undef QML_CRTYPE QQuickWindow* RingApplication::desktopWindow() const { static QQuickWindow* dw = nullptr; if (!dw) { QQmlComponent component(engine()); component.loadUrl(QUrl(QStringLiteral("qrc:/DesktopWindow.qml"))); if ( component.isReady() ) { qDebug() << "Previous error" << component.errorString(); auto obj2 = component.create(); // I have *no* clue why this is needed... A race somewhere while (component.errorString().isEmpty() && !obj2) obj2 = component.create(); if (!(dw = qobject_cast(obj2))) qWarning() << "Failed to load:" << component.errorString(); } else qWarning() << component.errorString(); } Q_ASSERT(dw); return dw; } -///The daemon is not found -void RingApplication::daemonTimeout() -{ - if ((!Session::instance()->callModel()->isConnected()) || (!Session::instance()->callModel()->isValid())) { - KMessageBox::error(nullptr, ErrorMessage::NO_DAEMON_ERROR); - exit(1); - } -} - ///Exit gracefully bool RingApplication::notify (QObject* receiver, QEvent* e) { try { return QApplication::notify(receiver,e); } - catch (const Call::State& state) { - qDebug() << ErrorMessage::GENERIC_ERROR << "CallState" << state; - QTimer::singleShot(2500, this, &RingApplication::daemonTimeout); - } - catch (const Call::Action& state) { - qDebug() << ErrorMessage::GENERIC_ERROR << "Call Action" << state; - QTimer::singleShot(2500, this, &RingApplication::daemonTimeout); - } - catch (const QString& errorMessage) { - KMessageBox::error(nullptr,errorMessage); - QTimer::singleShot(2500, this, &RingApplication::daemonTimeout); - } - catch (const std::exception& e) { - qDebug() << ErrorMessage::GENERIC_ERROR << e.what(); - KMessageBox::error(nullptr,ErrorMessage::GENERIC_ERROR); - QTimer::singleShot(2500, this, &RingApplication::daemonTimeout); - - } catch (...) { Q_ASSERT(false); - qDebug() << ErrorMessage::GENERIC_ERROR; - KMessageBox::error(nullptr, ErrorMessage::GENERIC_ERROR); - QTimer::singleShot(2500, this, &RingApplication::daemonTimeout); + qDebug() << GENERIC_ERROR; + KMessageBox::error(nullptr, GENERIC_ERROR); } return false; } bool RingApplication::mayHaveFocus() { return m_HasFocus; } #include // kate: space-indent on; indent-width 3; replace-tabs on; diff --git a/src/ringapplication.h b/src/ringapplication.h index 273e0f5f..f20dd5eb 100644 --- a/src/ringapplication.h +++ b/src/ringapplication.h @@ -1,101 +1,93 @@ /*************************************************************************** * Copyright (C) 2009-2015 by Savoir-Faire Linux * * Author : Jérémy Quentin * * Emmanuel Lepage Vallee * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, 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 General Public License * * along with this program. If not, see . * **************************************************************************/ #ifndef RINGAPPLICATION_H #define RINGAPPLICATION_H #include //Qt class QEvent; class QQmlApplicationEngine; class QQuickWindow; //KF5 namespace KDeclarative { class KDeclarative; } //Ring class RingQmlWidgets; -class PhotoSelectorPlugin; class DesktopView; class DialView; class Call; class PhoneWindowEvent; ///RingApplication: Main application class RingApplication final : public QApplication { Q_OBJECT public: // Constructor RingApplication(int & argc, char ** argv); // Destructor virtual ~RingApplication(); // Manage new instances Q_INVOKABLE virtual int newInstance(); // Exit gracefully virtual bool notify (QObject* receiver, QEvent* e) override; //Getter bool startIconified() const; QQuickWindow* desktopWindow() const; static QQmlApplicationEngine* engine(); static RingApplication* instance(); - void init(); /** * An unreliable way to track the application focus * * It is better than nothing */ bool mayHaveFocus(); //Setter void setIconify(bool iconify); bool m_HasFocus {false}; private: //Attributes bool m_StartIconified {false}; - bool m_StartPhone {false}; - bool m_StartTimeLine {false}; static KDeclarative::KDeclarative* m_pDeclarative; static RingQmlWidgets* m_pQmlWidget; - static PhotoSelectorPlugin* m_pPhotoSelector; static RingApplication* m_spInstance; static DesktopView* m_pDesktopView; PhoneWindowEvent* m_pEventFilter {nullptr}; - -private Q_SLOTS: - void daemonTimeout(); }; #endif // RINGAPPLICATION_H // kate: space-indent on; indent-width 3; replace-tabs on; diff --git a/src/timeline/qml/contactheader.qml b/src/timeline/qml/contactheader.qml index afb42595..d14d3e19 100644 --- a/src/timeline/qml/contactheader.qml +++ b/src/timeline/qml/contactheader.qml @@ -1,417 +1,415 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, 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 General Public License * * along with this program. If not, see . * **************************************************************************/ import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.0 import Ring 1.0 -import org.kde.ringkde.jamicontactview 1.0 as JamiContactView - import RingQmlWidgets 1.0 -import PhotoSelectorPlugin 1.0 import org.kde.kirigami 2.2 as Kirigami import org.kde.ringkde.jamicontactview 1.0 as JamiContactView +import org.kde.ringkde.jamiphotoselector 1.0 as JamiPhotoSelector Rectangle { id: contactHeader property QtObject currentContactMethod: null property var currentIndividual: null property bool isMobile: false property bool isCompact: false color: "gray" height: 70 Layout.fillWidth: true property alias backgroundColor: contactHeader.color property var textColor: undefined property var cachedPhoto: undefined signal selectChat() signal selectVideo() onCurrentIndividualChanged: { if (!currentIndividual) { primaryName.text = i18n("N/A") contactPhoto.individual = null return } primaryName.text = currentIndividual ? currentIndividual.bestName : i18n("N/A") contactPhoto.individual = currentIndividual bookmarkSwitch.source = (currentIndividual && currentIndividual.hasBookmarks) ? "icons/bookmarked.svg" : "icons/not_bookmarked.svg" } onCurrentContactMethodChanged: { primaryName.text = currentContactMethod.bestName contactPhoto.contactMethod = currentContactMethod bookmarkSwitch.source = (currentContactMethod && currentContactMethod.bookmarked) ? "icons/bookmarked.svg" : "icons/not_bookmarked.svg" } Connections { target: currentIndividual onBookmarkedChanged: { bookmarkSwitch.source = (currentIndividual && currentIndividual.hasBookmarks) ? "icons/bookmarked.svg" : "icons/not_bookmarked.svg" } } Connections { target: currentIndividual onChanged: { primaryName.text = currentIndividual.bestName contactPhoto.individual = currentIndividual bookmarkSwitch.source = (currentIndividual && currentIndividual.hasBookmarks) ? "icons/bookmarked.svg" : "icons/not_bookmarked.svg" } } // Wrap the photo as AnchorChanges are unreliable for margins Item { id: photo width: contactHeader.height height: contactHeader.height JamiContactView.ContactPhoto { id: contactPhoto anchors.fill: parent anchors.verticalCenter: contactHeader.verticalCenter anchors.margins: contactHeader.state == "" ? 5 : 2 displayEmpty: false MouseArea { id: mouseArea anchors.fill: parent z: 100 hoverEnabled: true onClicked: { var component = Qt.createComponent("PhotoEditor.qml") if (component.status == Component.Ready) { var window = component.createObject(contactHeader) window.contactMethod = currentContactMethod } else console.log("ERROR", component.status, component.errorString()) } } Rectangle { anchors.fill: parent border.width: 1 border.color: Kirigami.Theme.disabledTextColor radius: 5 // Make sure the "add photo" text is readable color: (mouseArea.containsMouse && contactPhoto.hasPhoto) ? Kirigami.Theme.backgroundColor : "transparent" opacity: (mouseArea.containsMouse || (!contactPhoto.hasPhoto)) ? 1 : 0 Behavior on opacity { NumberAnimation {duration: 100; easing.type: Easing.OutQuad} } Behavior on color { ColorAnimation {duration: 100} } Text { text: i18n("Add\nPhoto") font.bold: true color: activePalette.text anchors.centerIn: parent horizontalAlignment: Text.AlignHCenter } } } } Text { id: primaryName anchors.leftMargin: 5 anchors.rightMargin: 5 anchors.left: photo.right anchors.verticalCenter: contactHeader.verticalCenter font.bold: true text: "My name" color: textColor verticalAlignment: Text.AlignVCenter } Image { id: bookmarkSwitch anchors.left: primaryName.right anchors.verticalCenter: contactHeader.verticalCenter anchors.rightMargin: 1 anchors.topMargin: 3 anchors.leftMargin: 5 height: 16 width: 16 source: (currentIndividual && currentIndividual.hasBookmarks) ? "icons/bookmarked.svg" : "icons/not_bookmarked.svg" z: 100 MouseArea { anchors.fill: parent onClicked: { mouse.accepted = true if (currentContactMethod) { currentContactMethod.bookmarked = !currentContactMethod.bookmarked return } var cm = currentIndividual.firstBookmark if (!cm) cm = currentIndividual.lastUsedContactMethod if (cm) cm.bookmarked = !cm.bookmarked console.log(currentIndividual.hasBookmarks, cm.bookmarked) } } } Item { id: separator anchors.left: bookmarkSwitch.right anchors.verticalCenter: contactHeader.verticalCenter width: 10 height: contactHeader.height - 10 Rectangle { height: parent.height -10 y: 5 width: 1 color: inactivePalette.text opacity: 0.2 anchors.horizontalCenter: parent.horizontalCenter } } MediaButtons { id: mediaButtons anchors.verticalCenter: contactHeader.verticalCenter anchors.left: separator.right anchors.leftMargin: 5 anchors.rightMargin: 5 width: parent.width > (x+preferredWidth) ? preferredWidth : ( parent.width >= (x+minimumWidth -10) ? minimumWidth : iconifiedWidth ) } Item { id: mediaAvailability anchors.left: mediaButtons.right anchors.right: contactHeader.right anchors.top: contactHeader.top anchors.bottom: contactHeader.bottom anchors.leftMargin: 5 // Display reasons why the media buttons are not present MediaAvailability { defaultSize: parent.height < 48 ? parent.height : 48 currentIndividual: contactHeader.currentIndividual anchors.verticalCenter: parent.verticalCenter } } states: [ State { name: "" when: (!isCompact) && (!isMobile) && (currentIndividual) PropertyChanges { target: contactHeader height: 70 } PropertyChanges { target: primaryName font.pointSize: Kirigami.Theme.defaultFont.pointSize } PropertyChanges { target: separator visible: true } PropertyChanges { target: photo anchors.margins: 10 } AnchorChanges { target: photo anchors.horizontalCenter: undefined anchors.top: undefined anchors.verticalCenter: contactHeader.verticalCenter anchors.left: contactHeader.left } AnchorChanges { target: primaryName anchors.left: photo.right anchors.horizontalCenter: undefined anchors.top: undefined anchors.right: undefined anchors.verticalCenter: contactHeader.verticalCenter } AnchorChanges { target: bookmarkSwitch anchors.left: primaryName.right anchors.top: undefined anchors.right: undefined anchors.verticalCenter: contactHeader.verticalCenter } AnchorChanges { target: mediaButtons anchors.left: separator.left anchors.top: undefined anchors.right: undefined anchors.verticalCenter: contactHeader.verticalCenter } }, State { name: "empty" extend: "" when: (!currentIndividual) PropertyChanges { target: separator visible: false } PropertyChanges { target: contactPhoto visible: false } PropertyChanges { target: bookmarkSwitch visible: false } }, State { name: "compact" extend: "" when: isCompact && !isMobile PropertyChanges { target: contactHeader height: 40 } PropertyChanges { target: photo anchors.margins: 2 } PropertyChanges { target: mediaButtons visible: false } PropertyChanges { target: separator visible: false } }, State { name: "mobile" when: isMobile PropertyChanges { target: contactHeader height: photo.height + mediaButtons.implicitHeight + primaryName.implicitHeight + 10 // margins and spacing } AnchorChanges { target: photo anchors.horizontalCenter: contactHeader.horizontalCenter anchors.top: contactHeader.top anchors.left: undefined anchors.verticalCenter: undefined } AnchorChanges { target: primaryName anchors.top: photo.bottom anchors.horizontalCenter: contactHeader.horizontalCenter anchors.left: undefined anchors.right: undefined anchors.verticalCenter: undefined } AnchorChanges { target: bookmarkSwitch anchors.left: undefined anchors.top: contactHeader.top anchors.right: contactHeader.right anchors.verticalCenter: undefined } AnchorChanges { target: mediaButtons anchors.left: undefined anchors.top: undefined anchors.right: undefined anchors.bottom: contactHeader.bottom anchors.verticalCenter: undefined anchors.horizontalCenter: contactHeader.horizontalCenter } AnchorChanges { target: mediaAvailability anchors.left: contactHeader.left anchors.top: contactHeader.top anchors.right: undefined anchors.bottom: undefined anchors.verticalCenter: undefined anchors.horizontalCenter: undefined } PropertyChanges { target: photo height: 50 width: 50 anchors.margins: 2 } PropertyChanges { target: primaryName font.pointSize: Kirigami.Theme.defaultFont.pointSize*1.5 } PropertyChanges { target: separator visible: false } } ] } diff --git a/src/timeline/qml/contactinfo.qml b/src/timeline/qml/contactinfo.qml index 576068e3..06be660a 100644 --- a/src/timeline/qml/contactinfo.qml +++ b/src/timeline/qml/contactinfo.qml @@ -1,715 +1,713 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, 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 General Public License * * along with this program. If not, see . * **************************************************************************/ import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.2 import Ring 1.0 -import PhotoSelectorPlugin 1.0 import RingQmlWidgets 1.0 import org.kde.kirigami 2.2 as Kirigami -import org.kde.ringkde.jamicontactview 1.0 as JamiContactView import net.lvindustries.ringqtquick 1.0 as RingQtQuick import org.kde.ringkde.jamicontactview 1.0 as JamiContactView Kirigami.ScrollablePage { id: contactViewPage property string defaultName: "" property var individual: null property string forcedState: "" property bool editable: true property bool editing: editable signal changed() signal selectChat() signal selectHistory() property bool showStat: true property bool showImage: false property bool showSave: true property bool isChanged: false property var labelColor: inactivePalette.text property var cachedPhoto: undefined state: forcedState // verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff // horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff function save() { if (!individual) return var person = individual.person if (!person) person = contactBuilder.from(individual, vCardForm.name) if (!vCardForm.currentPerson) vCardForm.currentPerson = person vCardForm.syncDetails(person) if (contactViewPage.cachedPhoto != undefined) person.photo = contactViewPage.cachedPhoto person.save() //currentPerson = person isChanged = false } onChanged: { isChanged = true } SystemPalette { id: activePalette colorGroup: SystemPalette.Active } SystemPalette { id: inactivePalette colorGroup: SystemPalette.Inactive } actions { main: Kirigami.Action { iconName: editing ? "document-save" : "document-edit" visible: contactViewPage.state == "mobile" onTriggered: { if (editing && isChanged) { console.log("Saving!") contactViewPage.save() } editing = (!editing) && editable } } } onIndividualChanged: { vCardForm.currentPerson = individual ? individual.person : null vCardForm.individual = individual isChanged = false } GroupBox { id: advanced title: i18n("Advanced") clip: true height: 300 Behavior on height { NumberAnimation { duration: 200 } } ColumnLayout { id: tabbedContactInfo anchors.topMargin: contactViewPage.showImage ? 95 : 0 spacing: 0 clip: true anchors.fill: parent TabBar { Layout.fillWidth: true id: tabBar onCurrentIndexChanged: { sv.currentIndex = currentIndex } TabButton { text: i18n("Phone numbers") } // TabButton { // text: i18n("Addresses") // } } SwipeView { id: sv Layout.fillWidth: true Layout.fillHeight: true onCurrentIndexChanged: { tabBar.currentIndex = currentIndex } background: Rectangle { color: activePalette.base } Page { Layout.fillWidth: true Layout.fillHeight: true id: tabbedContactInfoPage1 VCardForm { id: vCardForm height: preferredHeight editing: contactViewPage.editing onChanged: { isChanged = true } } background: Rectangle { color: activePalette.base } } Page { id: phoneNumbersPage Layout.fillWidth: true Layout.fillHeight: true PhoneNumbers { id: phoneNumbers width: parent.width model: contactViewPage.individual buttonColor: contactViewPage.labelColor showAdd: contactViewPage.editing } background: Rectangle { color: activePalette.base } } // Page { // id: addressesPage // Layout.fillWidth: true // Layout.fillHeight: true // Addresses { // id: addresses // anchors.fill: parent // } // // background: Rectangle { color: activePalette.base } // } Page { Layout.fillWidth: true Layout.fillHeight: true background: Rectangle { color: activePalette.base } id: tabbedContactInfoPage4 Statistics { id: statistics Layout.fillWidth: true visible: showStat individual: contactViewPage.individual labelColor: contactViewPage.labelColor } } } } } RingQtQuick.ContactBuilder { id: contactBuilder } Rectangle { id: saveButton z: 10 radius: 999 color: activePalette.highlight visible: showSave && isChanged anchors.margins: 10 width: 56 height: 56 Image { source: "image://icon/edit-save" height: 32 width: 32 anchors.centerIn: parent } MouseArea { anchors.fill: parent hoverEnabled: true onClicked: { contactViewPage.save() } } } ColumnLayout { id: phoneLayout visible: false anchors.left: parent.left anchors.top: parent.top width: parent.width spacing: 10 /** * When showing the profile or adding a contact, display the image at the top. * * When showing the main GUI, this image is part of the header and should * not be shown. */ Item { id: contactPicture visible: showImage height: showImage ? 90 : 0 implicitHeight: showImage ? 90 : 0 Layout.fillWidth: true JamiContactView.ContactPhoto { id: photoRect tracked: false visible: showImage anchors.centerIn: parent height: 90 width: 90 defaultColor: contactViewPage.labelColor individual: contactViewPage.individual function onNewPhoto(p) { contactViewPage.cachedPhoto = p contactViewPage.changed() } MouseArea { anchors.fill: parent z: 100 onClicked: { if (!contactViewPage.editing) return false var component = Qt.createComponent("PhotoEditor.qml") if (component.status == Component.Ready) { var window = component.createObject(contactViewPage) window.person = individual ? individual.person : null window.newPhoto.connect(photoRect.onNewPhoto) } else console.log("ERROR", component.status, component.errorString()) } } } } Kirigami.Heading { id: statisticHeader text: i18n("Statistics") color: contactViewPage.labelColor level: 2 } Item { id: statisticHolder // Layout.leftAnchor: parent.left height: statistics.implicitHeight Layout.fillWidth: true } // Keep in columns to avoid spacing ColumnLayout { Layout.fillWidth: true Kirigami.BasicListItem { id: viewHistory label: i18n("View history") icon: "view-history" separatorVisible: true onClicked: { contactViewPage.selectHistory() } } Kirigami.BasicListItem { id: openChat label: i18n("Open chat") icon: "dialog-messages" onClicked: { contactViewPage.selectChat() } } } Kirigami.Heading { text: i18n("Contact details") color: contactViewPage.labelColor level: 2 } Item { id: contactHolder height: vCardForm.preferredHeight Layout.preferredHeight: height Layout.maximumHeight: height Layout.minimumHeight: height Layout.fillWidth: true } Kirigami.Heading { text: i18n("Phone numbers") color: contactViewPage.labelColor level: 2 } Item { id: phoneNumberHolder height: phoneNumbers.preferredHeight Layout.preferredHeight: height Layout.maximumHeight: height Layout.minimumHeight: height Layout.fillWidth: true } // Kirigami.Heading { // text: i18n("Addresses") // color: contactViewPage.labelColor // level: 2 // } // Item { // id: addressesHolder // height: addresses.contentHeight // width: parent.width // } } onStateChanged: { tabBar.currentIndex = 0 sv.currentIndex = 1 } /** * To make this page scale down, reparent everything depending on the * resolution. */ states: [ // In tablet mode, use 3 columns for the details State { name: "tablet" when: (forcedState == "" ) && (contactViewPage.width >= 600 && contactViewPage.height <= ( statistics.implicitHeight + 320) // 320 = advanced.height + 2*spacing ) ParentChange { target: advanced parent: contactViewPage } ParentChange { target: vCardForm parent: contactViewPage } ParentChange { target: statistics parent: contactViewPage } ParentChange { target: phoneNumbers parent: phoneNumbersPage } // ParentChange { // target: addresses // parent: addressesPage // } AnchorChanges { target: advanced anchors.right: advanced.parent.right anchors.bottom: advanced.parent.bottom anchors.top: contactPicture.bottom anchors.left: undefined } AnchorChanges { target: statistics anchors.top: contactPicture.visible ? contactPicture.bottom : contactViewPage.top anchors.left: statistics.parent.left } AnchorChanges { target: vCardForm anchors.left: vCardForm.parent.left anchors.top: statistics.bottom } AnchorChanges { target: phoneNumbers anchors.left: undefined anchors.top: undefined } // AnchorChanges { // target: addresses // anchors.left: undefined // } PropertyChanges { target: advanced visible: true width: contactViewPage.width / 2 height: contactViewPage.height } PropertyChanges { target: statistics width: contactViewPage.width / 2 height: statistics.implicitHeight } PropertyChanges { target: vCardForm width: contactViewPage.width / 2 } PropertyChanges { target: phoneNumbers anchors.fill: phoneNumbersPage width: undefined height: phoneNumbersPage.height interactive: true } PropertyChanges { target: contactViewPage editing: editable } AnchorChanges { target: saveButton anchors.bottom: saveButton.parent.bottom anchors.top: undefined anchors.left: saveButton.parent.left anchors.right: undefined anchors.horizontalCenter: undefined } PropertyChanges { target: saveButton width: 64 height: 64 } }, // In desktop mode, put everything on top of each other and get rid // of the second tabbar State { name: "" extend: "tablet" AnchorChanges { target: saveButton anchors.top: saveButton.parent.top anchors.right: saveButton.parent.right anchors.bottom: undefined anchors.left: undefined anchors.horizontalCenter: undefined } PropertyChanges { target: saveButton width: 64 height: 64 } AnchorChanges { target: advanced anchors.right: advanced.parent.right anchors.bottom: advanced.parent.bottom anchors.top: undefined anchors.left: advanced.parent.left } PropertyChanges { target: statistics width: contactViewPage.width } PropertyChanges { target: vCardForm width: vCardForm.implicitWidth height: vCardForm.implicitHeight anchors.topMargin: 10 anchors.horizontalCenter: undefined } PropertyChanges { target: advanced height: contactViewPage.height ? 300 : 299 //BUG prevent a race condition in QML visible: true anchors.topMargin: 10 } }, // The first phone mode was not very usable, lets try again State { name: "mobile" when: ((forcedState == "" && (contactViewPage.width < 600 || contactViewPage.height < ( statistics.implicitHeight + vCardForm.implicitHeight + 320) // 320 = advanced.height + 2*spacing ))) || forcedState == "mobile" // Mute the QML warning about having elements with anchors in `Column` AnchorChanges { target: saveButton anchors.right: undefined anchors.bottom: undefined anchors.top: undefined anchors.left: undefined anchors.horizontalCenter: undefined } AnchorChanges { target: advanced anchors.right: undefined anchors.bottom: undefined anchors.top: undefined anchors.left: undefined } ParentChange { target: vCardForm parent: contactHolder } AnchorChanges { target: vCardForm anchors.left: contactHolder.left anchors.top: contactHolder.top } PropertyChanges { target: vCardForm anchors.horizontalCenter: undefined } ParentChange { target: phoneNumbers parent: phoneNumberHolder } AnchorChanges { target: phoneNumbers anchors.left: phoneNumberHolder.left anchors.top: phoneNumberHolder.top } // ParentChange { // target: addresses // parent: addressesHolder // } // AnchorChanges { // target: addresses // anchors.left: contactViewPage.left // } ParentChange { target: statistics parent: statisticHolder } AnchorChanges { target: statistics anchors.left: statisticHolder.left anchors.top: statisticHolder.top } PropertyChanges { target: phoneNumbers anchors.fill: undefined width: contactViewPage.width interactive: false height: preferredHeight x: 0 y: 0 } // PropertyChanges { // target: addresses // anchors.fill: undefined // } PropertyChanges { target: phoneLayout visible: true } // Hide the tabs and groupbox in favor of standard rows PropertyChanges { target: advanced visible: false } PropertyChanges { target: tabBar visible: false } PropertyChanges { target: sv visible: false } PropertyChanges { target: contactViewPage bottomPadding: undefined topPadding: undefined leftPadding: undefined rightPadding: undefined editing: false } }, State { name: "profile" extend: "mobile" PropertyChanges { target: openChat visible: false } PropertyChanges { target: vCardForm anchors.horizontalCenter: contactHolder.horizontalCenter } PropertyChanges { target: statisticHolder visible: false } PropertyChanges { target: viewHistory visible: false } PropertyChanges { target: statisticHeader visible: false } PropertyChanges { target: contactViewPage bottomPadding: 0 topPadding: 0 leftPadding: 0 rightPadding: 0 editing: editable } AnchorChanges { target: phoneLayout anchors.top: contactPicture.bottom } } ] transitions: Transition { AnchorAnimation { duration: 300 } } } diff --git a/src/timeline/qml/mediabuttons.qml b/src/timeline/qml/mediabuttons.qml index 3e87f9e4..fd7fbc9c 100644 --- a/src/timeline/qml/mediabuttons.qml +++ b/src/timeline/qml/mediabuttons.qml @@ -1,437 +1,436 @@ /*************************************************************************** * Copyright (C) 2017-2018 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, 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 General Public License * * along with this program. If not, see . * **************************************************************************/ import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.0 import Ring 1.0 import org.kde.ringkde.jamicontactview 1.0 as JamiContactView import RingQmlWidgets 1.0 -import PhotoSelectorPlugin 1.0 import net.lvindustries.ringqtquick 1.0 as RingQtQuick import net.lvindustries.ringqtquick.media 1.0 as RingQtMedia Grid { id: container //TODO Qt5.10 deps: use native icons spacing: 5 leftPadding: 5 rows: 1 property real button1IW: button.visible ? button.implicitWidth + 5 : 0 property real button2IW: button2.visible ? button2.implicitWidth + 5 : 0 property real button3IW: button3.visible ? button3.implicitWidth + 5 : 0 property real button4IW: button4.visible ? button4.implicitWidth + 5 : 0 // Favor being on one row, but allow 2 rows too property real preferredWidth: Math.max(preferredWidth, button1IW + button2IW + button3IW + button4IW ) property real minimumWidth: (button3.visible ? maximumButtonWidth * 2 : 0) + 15 property real iconifiedWidth: 4*button.implicitHeight + 20 property real maximumButtonWidth: Math.max(maximumButtonWidth, button3.implicitWidth) states: [ State { extend: "" name: "2rows" when: width > iconifiedWidth && width <= minimumWidth PropertyChanges { target: container rows: 2 } PropertyChanges { target: button width: maximumButtonWidth } PropertyChanges { target: button2 width: maximumButtonWidth } PropertyChanges { target: button3 width: maximumButtonWidth } PropertyChanges { target: button4 width: maximumButtonWidth } }, State { name: "" when: width > minimumWidth PropertyChanges { target: container rows: 1 } PropertyChanges { target: textLabel1 visible: true } PropertyChanges { target: textLabel2 visible: true } PropertyChanges { target: textLabel3 visible: true } PropertyChanges { target: textLabel4 visible: true } PropertyChanges { target: button width: undefined } PropertyChanges { target: button2 width: undefined } PropertyChanges { target: button3 width: undefined } PropertyChanges { target: button4 width: undefined } }, State { name: "iconified" extend: "" when: width <= iconifiedWidth PropertyChanges { target: container rows: 1 } PropertyChanges { target: textLabel1 visible: false } PropertyChanges { target: textLabel2 visible: false } PropertyChanges { target: textLabel3 visible: false } PropertyChanges { target: textLabel4 visible: false } } ] function getContactMethod(callback) { if (currentIndividual == null) return if (currentIndividual.requireUserSelection) { var component = Qt.createComponent("CMSelector.qml") if (component.status == Component.Ready) { var window = component.createObject(applicationWindow().contentItem) window.currentIndividual = currentIndividual window.callback = callback window.open() } else console.log("ERROR", component.status, component.errorString()) return } var cm = currentIndividual.mainContactMethod if (!cm) return if (callback) callback(cm) return cm } RingQtMedia.AvailabilityTracker { id: availabilityTracker individual: currentIndividual } Button { id: button implicitWidth: label.implicitWidth + 20 visible: availabilityTracker.canCall checkable: checked checked: availabilityTracker.audioCallControlState == RingQtMedia.AvailabilityTracker.CHECKED onClicked: { focus = false if (checked) return // Do not create a new call, just switch the media if (currentIndividual && currentIndividual.firstActiveCall) { contactHeader.selectVideo() currentIndividual.firstActiveCall.sourceModel.switchTo(0) return } getContactMethod(function(cm) { if (!cm) return if (cm.hasInitCall) { contactHeader.selectVideo() return } var call = RingSession.callModel.dialingCall(cm) call.removeMedia(RingQtMedia.Media.VIDEO) call.performAction(RingQtQuick.Call.ACCEPT) }) } Row { id: label anchors.centerIn: parent height: parent.height Image { height: 22 width: 22 sourceSize.width: 22 sourceSize.height: 22 anchors.verticalCenter: parent.verticalCenter source: "image://SymbolicColorizer/:/sharedassets/outline/call.svg" } Text { id: textLabel1 anchors.margins: 5 height: parent.height verticalAlignment: Text.AlignVCenter color: activePalette.text text: " " + i18n("Call") } } } Button { id: button2 implicitWidth: label2.implicitWidth + 20 visible: availabilityTracker.canVideoCall checkable: checked checked: availabilityTracker.videoCallControlState == RingQtMedia.AvailabilityTracker.CHECKED onClicked: { focus = false if (checked) return // Do not create a new call, just switch the media if (currentIndividual && currentIndividual.firstActiveCall) { contactHeader.selectVideo() currentIndividual.firstActiveCall.sourceModel.switchTo(3) return } getContactMethod(function(cm) { if (!cm) return if (cm.hasInitCall) { contactHeader.selectVideo() return } RingSession.callModel.dialingCall(cm) .performAction(RingQtQuick.Call.ACCEPT) }) } Row { id: label2 anchors.centerIn: parent height: parent.height Image { height: 22 width: 22 sourceSize.width: 22 sourceSize.height: 22 anchors.verticalCenter: parent.verticalCenter source: "image://SymbolicColorizer/:/sharedassets/outline/camera.svg" } Text { id: textLabel2 anchors.margins: 5 height: parent.height verticalAlignment: Text.AlignVCenter color: activePalette.text text: " " + i18n("Video") } } } Button { id: button3 implicitWidth: label3.implicitWidth + 20 checkable: checked checked: availabilityTracker.screenSharingControlState == RingQtMedia.AvailabilityTracker.CHECKED visible: availabilityTracker.canVideoCall onClicked: { focus = false if (checked) return // Do not create a new call, just switch the media if (currentIndividual && currentIndividual.firstActiveCall) { contactHeader.selectVideo() currentIndividual.firstActiveCall.sourceModel.switchTo(1) return } getContactMethod(function(cm) { if (!cm) return if (cm.hasInitCall) { contactHeader.selectVideo() return } RingSession.callModel.dialingCall(cm) .performAction(RingQtQuick.Call.ACCEPT) }) } Row { id: label3 anchors.centerIn: parent height: parent.height Image { height: 22 width: 22 sourceSize.width: 22 sourceSize.height: 22 anchors.verticalCenter: parent.verticalCenter source: "image://SymbolicColorizer/:/sharedassets/outline/screen.svg" } Text { id: textLabel3 anchors.margins: 5 color: activePalette.text height: parent.height verticalAlignment: Text.AlignVCenter text: " " + i18n("Screen sharing") } } } Button { id: button4 implicitWidth: label4.implicitWidth + 20 visible: availabilityTracker.canSendTexts onClicked: { if (currentIndividual == null) return contactHeader.selectChat() } Row { id: label4 anchors.centerIn: parent height: parent.height Image { height: 22 width: 22 sourceSize.width: 22 sourceSize.height: 22 anchors.verticalCenter: parent.verticalCenter source: "image://SymbolicColorizer/:/sharedassets/outline/chat.svg" } Text { id: textLabel4 anchors.margins: 5 height: parent.height verticalAlignment: Text.AlignVCenter color: activePalette.text text: " " + i18n("Chat") } } Button { id: button5 implicitWidth: label4.implicitWidth + 20 text: i18n("Hang up") visible: availabilityTracker.hangUpControlState == RingQtMedia.AvailabilityTracker.NORMAL onClicked: { if (currentIndividual == null) return var c = currentIndividual.firstActiveCall if (!c) return c.performAction(RingQtQuick.Call.REFUSE) } } } }