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)
}
}
}
}