Commit 1e97071f authored by LNJ's avatar LNJ

Merge branch 'multimedia-messages'

Closes #287, #289.
parents 039a14a0 78b07ca6
Pipeline #11043 passed with stages
in 37 minutes and 52 seconds
......@@ -55,7 +55,7 @@ include(FeatureSummary)
kde_enable_exceptions()
# Find packages
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Core Qml Quick Svg Sql QuickControls2 Xml Multimedia)
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Core Qml Quick Svg Sql QuickControls2 Xml Multimedia Positioning Location)
find_package(KF5Kirigami2 REQUIRED)
find_package(ZXing REQUIRED COMPONENTS Core)
find_package(QXmpp 1.0.0 REQUIRED)
......@@ -168,6 +168,8 @@ target_link_libraries(${PROJECT_NAME}
Qt5::Network
Qt5::Xml
Qt5::Multimedia
Qt5::Positioning
Qt5::Location
ZXing::Core
QXmpp::QXmpp
${__Qt5Widgets_LIBRARIES}
......@@ -317,7 +319,10 @@ endif()
if(UBUNTU_TOUCH)
set(KAIDAN_COMPILE_DEFINITIONS UBUNTU_TOUCH=True)
elseif(APPIMAGE)
set(KAIDAN_COMPILE_DEFINITIONS APPIMAGE=True)
set(KAIDAN_COMPILE_DEFINITIONS
APPIMAGE=True
TARGET_GSTREAMER_PLUGINS="${TARGET_GSTREAMER_PLUGINS}"
)
endif()
if(STATIC_BUILD)
......
......@@ -39,7 +39,7 @@ how to do that:
### Dependencies
Here are the general dependencies of Kaidan listed:
* [Qt](https://doc.qt.io/qt-5/build-sources.html) (Core Qml Quick Svg Sql QuickControls2 Multimedia) (>= 5.10.0)
* [Qt](https://doc.qt.io/qt-5/build-sources.html) (Core Qml Quick Svg Sql QuickControls2 Xml Multimedia Positioning Location) (>= 5.10.0)
* [QXmpp][qxmpp] (>= 1.0.0)
* [Kirigami 2](https://phabricator.kde.org/source/kirigami/) (>= 5.42.0)
* [ECM (extra-cmake-modules)](https://api.kde.org/ecm/manual/ecm.7.html)
......
......@@ -9,6 +9,7 @@
<file alias="qml/EmptyChatPage.qml">src/qml/EmptyChatPage.qml</file>
<file alias="qml/QrCodeScannerPage.qml">src/qml/QrCodeScannerPage.qml</file>
<file alias="qml/UserProfilePage.qml">src/qml/UserProfilePage.qml</file>
<file alias="qml/MultimediaSettingsPage.qml">src/qml/MultimediaSettingsPage.qml</file>
<file alias="qml/elements/SubRequestAcceptSheet.qml">src/qml/elements/SubRequestAcceptSheet.qml</file>
<file alias="qml/elements/RosterAddContactSheet.qml">src/qml/elements/RosterAddContactSheet.qml</file>
......@@ -17,15 +18,25 @@
<file alias="qml/elements/RosterListItem.qml">src/qml/elements/RosterListItem.qml</file>
<file alias="qml/elements/MessageCounter.qml">src/qml/elements/MessageCounter.qml</file>
<file alias="qml/elements/ChatMessage.qml">src/qml/elements/ChatMessage.qml</file>
<file alias="qml/elements/ChatMessageImage.qml">src/qml/elements/ChatMessageImage.qml</file>
<file alias="qml/elements/RoundImage.qml">src/qml/elements/RoundImage.qml</file>
<file alias="qml/elements/IconButton.qml">src/qml/elements/IconButton.qml</file>
<file alias="qml/elements/FileChooser.qml">src/qml/elements/FileChooser.qml</file>
<file alias="qml/elements/FileChooserDesktop.qml">src/qml/elements/FileChooserDesktop.qml</file>
<file alias="qml/elements/FileChooserMobile.qml">src/qml/elements/FileChooserMobile.qml</file>
<file alias="qml/elements/SendMediaSheet.qml">src/qml/elements/SendMediaSheet.qml</file>
<file alias="qml/elements/MediaPreview.qml">src/qml/elements/MediaPreview.qml</file>
<file alias="qml/elements/MediaPreviewImage.qml">src/qml/elements/MediaPreviewImage.qml</file>
<file alias="qml/elements/MediaPreviewAudio.qml">src/qml/elements/MediaPreviewAudio.qml</file>
<file alias="qml/elements/MediaPreviewVideo.qml">src/qml/elements/MediaPreviewVideo.qml</file>
<file alias="qml/elements/MediaPreviewOther.qml">src/qml/elements/MediaPreviewOther.qml</file>
<file alias="qml/elements/MediaPreviewLocation.qml">src/qml/elements/MediaPreviewLocation.qml</file>
<file alias="qml/elements/MediaPreviewLoader.qml">src/qml/elements/MediaPreviewLoader.qml</file>
<file alias="qml/elements/NewMedia.qml">src/qml/elements/NewMedia.qml</file>
<file alias="qml/elements/NewMediaLocation.qml">src/qml/elements/NewMediaLocation.qml</file>
<file alias="qml/elements/NewMediaLoader.qml">src/qml/elements/NewMediaLoader.qml</file>
<file alias="qml/elements/EmojiPicker.qml">src/qml/elements/EmojiPicker.qml</file>
<file alias="qml/elements/TextAvatar.qml">src/qml/elements/TextAvatar.qml</file>
<file alias="qml/elements/Avatar.qml">src/qml/elements/Avatar.qml</file>
......
......@@ -2,7 +2,7 @@
<qresource prefix="/icons/breeze">
<file alias="index.theme">3rdparty/breeze-icons/icons/index.theme</file>
</qresource>
<qresource prefix="/icons/breeze/actions/22">
<file alias="application-menu.svg">3rdparty/breeze-icons/icons/actions/22/application-menu.svg</file>
<file alias="document-decrypt.svg">3rdparty/breeze-icons/icons/actions/22/document-decrypt.svg</file>
......@@ -38,33 +38,48 @@
<file alias="user-identity.svg">3rdparty/breeze-icons/icons/actions/22/user-identity.svg</file>
<file alias="edit-rename.svg">3rdparty/breeze-icons/icons/actions/22/edit-rename.svg</file>
<file alias="delete.svg">3rdparty/breeze-icons/icons/actions/22/delete.svg</file>
<file alias="dialog-cancel.svg">3rdparty/breeze-icons/icons/actions/24/dialog-cancel.svg</file>
<file alias="dialog-ok-apply.svg">3rdparty/breeze-icons/icons/actions/24/dialog-ok-apply.svg</file>
</qresource>
<qresource prefix="/icons/breeze/emotes/22">
<file alias="face-smile.svg">3rdparty/breeze-icons/icons/emotes/22/face-smile.svg</file>
</qresource>
<qresource prefix="/icons/breeze/actions/16">
<file alias="document-send.svg">3rdparty/breeze-icons/icons/actions/16/document-send.svg</file>
<file alias="search.svg">3rdparty/breeze-icons/icons/actions/16/search.svg</file>
<file alias="gps.svg">3rdparty/breeze-icons/icons/actions/16/gps.svg</file>
</qresource>
<qresource prefix="/icons/breeze/actions/symbolic">
<file alias="document-send-symbolic.svg">3rdparty/breeze-icons/icons/actions/symbolic/document-send-symbolic.svg</file>
<file alias="go-next-symbolic.svg">3rdparty/breeze-icons/icons/actions/symbolic/go-next-symbolic.svg</file>
<file alias="go-previous-symbolic.svg">3rdparty/breeze-icons/icons/actions/symbolic/go-previous-symbolic.svg</file>
<file alias="edit-symbolic.svg">3rdparty/breeze-icons/icons/actions/symbolic/edit-symbolic.svg</file>
</qresource>
<qresource prefix="/icons/breeze/applets/22">
<file alias="microphone.svg">3rdparty/breeze-icons/icons/applets/22/microphone.svg</file>
</qresource>
<qresource prefix="/icons/breeze/devices/symbolic">
<file alias="camera-photo-symbolic.svg">3rdparty/breeze-icons/icons/devices/symbolic/camera-photo-symbolic.svg</file>
<file alias="camera-video-symbolic.svg">3rdparty/breeze-icons/icons/devices/symbolic/camera-video-symbolic.svg</file>
</qresource>
<qresource prefix="/icons/breeze/mimetypes/64">
<file alias="image-jpeg.svg">3rdparty/breeze-icons/icons/mimetypes/64/image-jpeg.svg</file>
<file alias="video-mp4.svg">3rdparty/breeze-icons/icons/mimetypes/64/video-mp4.svg</file>
<file alias="x-office-document.svg">3rdparty/breeze-icons/icons/mimetypes/64/x-office-document.svg</file>
<file alias="audio-mp3.svg">3rdparty/breeze-icons/icons/mimetypes/64/audio-mp3.svg</file>
<file alias="video-x-generic.svg">3rdparty/breeze-icons/icons/mimetypes/64/video-x-generic.svg</file>
<file alias="application-octet-stream.svg">3rdparty/breeze-icons/icons/mimetypes/64/application-octet-stream.svg</file>
</qresource>
<qresource prefix="/icons/breeze/mimetypes/22">
<file alias="text-x-plain.svg">3rdparty/breeze-icons/icons/mimetypes/22/text-x-plain.svg</file>
<file alias="application-octet-stream.svg">3rdparty/breeze-icons/icons/mimetypes/22/application-octet-stream.svg</file>
</qresource>
<qresource prefix="/icons/status/symbolic">
......
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2019 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan 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.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan 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 Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#include "AudioDeviceModel.h"
static AudioDeviceInfo audioDeviceByDeviceName(QAudio::Mode mode, const QString &deviceName) {
const auto audioDevices(QAudioDeviceInfo::availableDevices(mode));
for (const auto &audioDevice: audioDevices) {
if (audioDevice.deviceName() == deviceName) {
return AudioDeviceInfo(audioDevice);
}
}
return AudioDeviceInfo();
}
AudioDeviceInfo::AudioDeviceInfo(const QAudioDeviceInfo &other)
: QAudioDeviceInfo(other)
{
}
QString AudioDeviceInfo::description() const
{
return description(deviceName());
}
QString AudioDeviceInfo::description(const QString &deviceName)
{
return QString(deviceName)
.replace(QLatin1Char(':'), QLatin1Char(' '))
.replace(QLatin1Char('='), QLatin1Char(' '))
.replace(QLatin1Char(','), QLatin1Char(' '))
.trimmed();
}
AudioDeviceModel::AudioDeviceModel(QObject *parent)
: QAbstractListModel(parent)
{
refresh();
connect(this, &AudioDeviceModel::modeChanged, this, &AudioDeviceModel::refresh);
}
int AudioDeviceModel::rowCount(const QModelIndex &parent) const
{
return parent == QModelIndex() ? m_audioDevices.count() : 0;
}
QVariant AudioDeviceModel::data(const QModelIndex &index, int role) const
{
if (hasIndex(index.row(), index.column(), index.parent())) {
const auto &audioDeviceInfo(m_audioDevices[index.row()]);
switch (role) {
case AudioDeviceModel::CustomRoles::IsNullRole:
return audioDeviceInfo.isNull();
case AudioDeviceModel::CustomRoles::DeviceNameRole:
return audioDeviceInfo.deviceName();
case AudioDeviceModel::CustomRoles::DescriptionRole:
return AudioDeviceInfo::description(audioDeviceInfo.deviceName());
case AudioDeviceModel::CustomRoles::SupportedCodecsRole:
return audioDeviceInfo.supportedCodecs();
case AudioDeviceModel::CustomRoles::SupportedSampleRatesRole:
return QVariant::fromValue(audioDeviceInfo.supportedSampleRates());
case AudioDeviceModel::CustomRoles::SupportedChannelCountsRole:
return QVariant::fromValue(audioDeviceInfo.supportedChannelCounts());
case AudioDeviceModel::CustomRoles::SupportedSampleSizesRole:
return QVariant::fromValue(audioDeviceInfo.supportedSampleSizes());
case AudioDeviceModel::CustomRoles::AudioDeviceInfoRole:
return QVariant::fromValue(AudioDeviceInfo(audioDeviceInfo));
}
}
return QVariant();
}
QHash<int, QByteArray> AudioDeviceModel::roleNames() const
{
static const QHash<int, QByteArray> roles {
{ IsNullRole, QByteArrayLiteral("isNull") },
{ DeviceNameRole, QByteArrayLiteral("deviceName") },
{ DescriptionRole, QByteArrayLiteral("description") },
{ SupportedCodecsRole, QByteArrayLiteral("supportedCodecs") },
{ SupportedSampleRatesRole, QByteArrayLiteral("supportedSampleRates") },
{ SupportedChannelCountsRole, QByteArrayLiteral("supportedChannelCounts") },
{ SupportedSampleSizesRole, QByteArrayLiteral("supportedSampleSizes") },
{ AudioDeviceInfoRole, QByteArrayLiteral("audioDeviceInfo") }
};
return roles;
}
AudioDeviceModel::Mode AudioDeviceModel::mode() const
{
return m_mode;
}
void AudioDeviceModel::setMode(AudioDeviceModel::Mode mode)
{
if (m_mode == mode) {
return;
}
m_mode = mode;
emit modeChanged();
}
QList<QAudioDeviceInfo> AudioDeviceModel::audioDevices() const
{
return m_audioDevices;
}
AudioDeviceInfo AudioDeviceModel::defaultAudioDevice() const
{
switch (m_mode) {
case AudioDeviceModel::Mode::AudioInput:
return defaultAudioInputDevice();
case AudioDeviceModel::Mode::AudioOutput:
return defaultAudioOutputDevice();
}
Q_UNREACHABLE();
return AudioDeviceInfo();
}
int AudioDeviceModel::currentIndex() const
{
return m_currentIndex;
}
void AudioDeviceModel::setCurrentIndex(int currentIndex)
{
if (currentIndex < 0 || currentIndex >= m_audioDevices.count()
|| m_currentIndex == currentIndex) {
return;
}
m_currentIndex = currentIndex;
emit currentIndexChanged();
}
AudioDeviceInfo AudioDeviceModel::currentAudioDevice() const
{
return m_currentIndex >= 0 && m_currentIndex < m_audioDevices.count()
? AudioDeviceInfo(m_audioDevices[m_currentIndex])
: AudioDeviceInfo();
}
void AudioDeviceModel::setCurrentAudioDevice(const AudioDeviceInfo &currentAudioDevice)
{
setCurrentIndex(m_audioDevices.indexOf(currentAudioDevice));
}
AudioDeviceInfo AudioDeviceModel::audioDevice(int row) const
{
return hasIndex(row, 0)
? AudioDeviceInfo(m_audioDevices[row])
: AudioDeviceInfo();
}
int AudioDeviceModel::indexOf(const QString &deviceName) const
{
for (int i = 0; i < m_audioDevices.count(); ++i) {
const auto &audioDevice(m_audioDevices[i]);
if (audioDevice.deviceName() == deviceName) {
return i;
}
}
return -1;
}
AudioDeviceInfo AudioDeviceModel::defaultAudioInputDevice()
{
return AudioDeviceInfo(QAudioDeviceInfo::defaultInputDevice());
}
AudioDeviceInfo AudioDeviceModel::audioInputDevice(const QString &deviceName)
{
return audioDeviceByDeviceName(QAudio::AudioInput, deviceName);
}
AudioDeviceInfo AudioDeviceModel::defaultAudioOutputDevice()
{
return AudioDeviceInfo(QAudioDeviceInfo::defaultOutputDevice());
}
AudioDeviceInfo AudioDeviceModel::audioOutputDevice(const QString &deviceName)
{
return audioDeviceByDeviceName(QAudio::AudioOutput, deviceName);
}
void AudioDeviceModel::refresh()
{
const auto audioDevices = QAudioDeviceInfo::availableDevices(static_cast<QAudio::Mode>(m_mode));
if (m_audioDevices == audioDevices) {
return;
}
beginResetModel();
const QString currentDeviceName = currentAudioDevice().deviceName();
const auto it = std::find_if(m_audioDevices.constBegin(), m_audioDevices.constEnd(),
[&currentDeviceName](const QAudioDeviceInfo &deviceInfo) {
return deviceInfo.deviceName() == currentDeviceName;
});
m_audioDevices = audioDevices;
m_currentIndex = it == m_audioDevices.constEnd() ? -1 : it - m_audioDevices.constBegin();
endResetModel();
emit audioDevicesChanged();
emit currentIndexChanged();
}
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2019 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan 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.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan 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 Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QAudioDeviceInfo>
#include <QAbstractListModel>
class AudioDeviceInfo : public QAudioDeviceInfo {
Q_GADGET
Q_PROPERTY(bool isNull READ isNull CONSTANT)
Q_PROPERTY(QString deviceName READ deviceName CONSTANT)
Q_PROPERTY(QString description READ description CONSTANT)
Q_PROPERTY(QStringList supportedCodecs READ supportedCodecs CONSTANT)
Q_PROPERTY(QList<int> supportedSampleRates READ supportedSampleRates CONSTANT)
Q_PROPERTY(QList<int> supportedChannelCounts READ supportedChannelCounts CONSTANT)
Q_PROPERTY(QList<int> supportedSampleSizes READ supportedSampleSizes CONSTANT)
public:
using QAudioDeviceInfo::QAudioDeviceInfo;
AudioDeviceInfo(const QAudioDeviceInfo &other);
AudioDeviceInfo() = default;
QString description() const;
static QString description(const QString &deviceName);
};
class AudioDeviceModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(AudioDeviceModel::Mode mode READ mode WRITE setMode NOTIFY modeChanged)
Q_PROPERTY(int rowCount READ rowCount NOTIFY audioDevicesChanged)
Q_PROPERTY(QList<QAudioDeviceInfo> audioDevices READ audioDevices NOTIFY audioDevicesChanged)
Q_PROPERTY(AudioDeviceInfo defaultAudioDevice READ defaultAudioDevice NOTIFY audioDevicesChanged)
Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
Q_PROPERTY(AudioDeviceInfo currentAudioDevice READ currentAudioDevice WRITE setCurrentAudioDevice NOTIFY currentIndexChanged)
public:
enum Mode {
AudioInput = QAudio::Mode::AudioInput,
AudioOutput = QAudio::Mode::AudioOutput
};
Q_ENUM(Mode)
enum CustomRoles {
IsNullRole = Qt::UserRole,
DeviceNameRole,
DescriptionRole,
SupportedCodecsRole,
SupportedSampleRatesRole,
SupportedChannelCountsRole,
SupportedSampleSizesRole,
AudioDeviceInfoRole
};
explicit AudioDeviceModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
AudioDeviceModel::Mode mode() const;
void setMode(AudioDeviceModel::Mode mode);
QList<QAudioDeviceInfo> audioDevices() const;
AudioDeviceInfo defaultAudioDevice() const;
int currentIndex() const;
void setCurrentIndex(int currentIndex);
AudioDeviceInfo currentAudioDevice() const;
void setCurrentAudioDevice(const AudioDeviceInfo &currentAudioDevice);
Q_INVOKABLE AudioDeviceInfo audioDevice(int row) const;
Q_INVOKABLE int indexOf(const QString &deviceName) const;
static AudioDeviceInfo defaultAudioInputDevice();
static AudioDeviceInfo audioInputDevice(const QString &deviceName);
static AudioDeviceInfo defaultAudioOutputDevice();
static AudioDeviceInfo audioOutputDevice(const QString &deviceName);
public slots:
void refresh();
signals:
void modeChanged();
void audioDevicesChanged();
void currentIndexChanged();
private:
AudioDeviceModel::Mode m_mode = AudioDeviceModel::Mode::AudioInput;
QList<QAudioDeviceInfo> m_audioDevices;
int m_currentIndex = -1;
};
Q_DECLARE_METATYPE(AudioDeviceInfo)
......@@ -28,9 +28,15 @@ set(KAIDAN_SOURCES
src/DownloadManager.cpp
src/QmlUtils.cpp
src/Utils.cpp
src/QrCodeDecoder
src/QrCodeDecoder.cpp
src/QrCodeScannerFilter.cpp
src/QrCodeVideoFrame.cpp
src/CameraModel.cpp
src/AudioDeviceModel.cpp
src/MediaSettings.cpp
src/CameraImageCapture.cpp
src/MediaUtils.cpp
src/MediaRecorder.cpp
# needed to trigger moc generation / to be displayed in IDEs
src/Enums.h
......
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2019 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan 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.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan 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 Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CameraImageCapture.h"
CameraImageCapture::CameraImageCapture(QMediaObject *mediaObject, QObject *parent)
: QCameraImageCapture(mediaObject, parent)
{
connect(this, &QCameraImageCapture::imageSaved,
this, [this](int id, const QString &filePath) {
Q_UNUSED(id);
m_actualLocation = QUrl::fromLocalFile(filePath);
emit actualLocationChanged(m_actualLocation);
});
}
QUrl CameraImageCapture::actualLocation() const
{
return m_actualLocation;
}
bool CameraImageCapture::setMediaObject(QMediaObject *mediaObject)
{
const QMultimedia::AvailabilityStatus previousAvailability = availability();
const bool result = QCameraImageCapture::setMediaObject(mediaObject);
if (previousAvailability != availability()) {
QMetaObject::invokeMethod(this, [this]() {
emit availabilityChanged(availability());
}, Qt::QueuedConnection);
}
return result;
}
......@@ -28,16 +28,33 @@
* along with Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
#pragma once
AnimatedImage {
id: image
#include <QCameraImageCapture>
#include <QUrl>
source: sourceUrl
fillMode: Image.PreserveAspectFit
// A QCameraImageCapture that mimic api of QMediaRecorder
MouseArea {
anchors.fill: parent
onClicked: Qt.openUrlExternally(sourceUrl)
}
}
class CameraImageCapture : public QCameraImageCapture
{
Q_OBJECT
Q_PROPERTY(QUrl actualLocation READ actualLocation NOTIFY actualLocationChanged)
Q_PROPERTY(QMultimedia::AvailabilityStatus availability READ availability NOTIFY availabilityChanged)
Q_PROPERTY(bool isAvailable READ isAvailable NOTIFY availabilityChanged)
public:
CameraImageCapture(QMediaObject *mediaObject, QObject *parent = nullptr);
QUrl actualLocation() const;
signals:
void availabilityChanged(QMultimedia::AvailabilityStatus availability);
void actualLocationChanged(const QUrl &location);
protected:
bool setMediaObject(QMediaObject *mediaObject) override;
private:
QUrl m_actualLocation;
};
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2019 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan 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.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan 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 Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CameraModel.h"
CameraInfo::CameraInfo(const QString &deviceName)
: QCameraInfo(deviceName.toLocal8Bit())
{
}
CameraInfo::CameraInfo(const QCameraInfo &other)
: QCameraInfo(other)
{
}
CameraModel::CameraModel(QObject *parent)
: QAbstractListModel(parent)
{
refresh();
}
int CameraModel::rowCount(const QModelIndex &parent) const
{
return parent == QModelIndex() ? m_cameras.count() : 0;
}
QVariant CameraModel::data(const QModelIndex &index, int role) const
{
if (hasIndex(index.row(), index.column(), index.parent())) {
const auto &cameraInfo(m_cameras[index.row()]);
switch (role) {
case CameraModel::CustomRoles::IsNullRole:
return cameraInfo.isNull();
case CameraModel::CustomRoles::DeviceNameRole:
return cameraInfo.deviceName();
case CameraModel::CustomRoles::DescriptionRole:
return cameraInfo.description();
case CameraModel::CustomRoles::PositionRole:
return cameraInfo.position();
case CameraModel::CustomRoles::OrientationRole:
return cameraInfo.orientation();
case CameraModel::CustomRoles::CameraInfoRole:
return QVariant::fromValue(CameraInfo(cameraInfo));
}
}
return QVariant();
}
QHash<int, QByteArray> CameraModel::roleNames() const
{
static const QHash<int, QByteArray> roles {
{ IsNullRole, QByteArrayLiteral("isNull") },
{ DeviceNameRole, QByteArrayLiteral("deviceName") },
{ DescriptionRole, QByteArrayLiteral("description") },
{ PositionRole, QByteArrayLiteral("position") },
{ OrientationRole, QByteArrayLiteral("orientation") },